线段树(小整理)

求区间和;

LL sum[maxn<<2];//保存区间和
LL add[maxn<<2];//懒惰标记
LL a[maxn];//用于输入保存数据

求区间和的函数:

void pushup(int x)
{
    sum[x]=sum[x<<1]+sum[x<<1|1];
}

建立线段树:

void buildtree(int l,int r,int rt)
{
    if(l==r){
        sum[rt]=a[l];//叶子节点的插入
        return ;
    }
    int m=(l+r)>>1;
    buildtree(l,m,rt<<1);//建立左子树
    buildtree(m+1,r,rt<<1|1);//右子树
    pushup(rt);//维护各区间的加和
}

单点修改:

void singlemodify(int X,int L,int l,int r,int rt)
{
    if(l==r){
        //a[L]+=X;
        sum[rt]+=X;
        return  ;
    }
    int m=(l+r)>>1;
    if(m>L){
        singlemodify(X,L,l,m,rt<<1);//查询左边
    }
    else singlemodify(X,L,m+1,r,rt<<1|1);//查询右边
    pushup(rt);//更新区间
}

区间修改:

void qmodify(int X,int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R){
        sum[rt]+=(r-l+1)*X;
        add[rt]+=X;
        return ;
    }
    int m=(l+r)>>1;
    pushdown(r-m,m-l+1,rt);
    if(m>=L) qmodify(X,L,R,l,m,rt<<1);
    if(R>m) qmodify(X,L,R,m+1,r,rt<<1|1);
    pushup(rt);
}

延时标记函数

void pushdown(int rn,int ln,int rt)
{//对于有标记的节点,说明该节点之后的节点没有修改
    if(add[rt]){
        sum[rt<<1]+=ln*add[rt];
        sum[rt<<1|1]+=rn*add[rt];
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        add[rt]=0;
    }
    return ;
}

查询:

LL query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R){
        return sum[rt];
    }
    int m=(l+r)>>1;
    pushdown(r-m,m-l+1,rt);//注意标记下推,因为可能会查询到未修改的节点
    LL ans=0;
    if(m>=L) ans+=query(L,R,l,m,rt<<1);
    if(m<R) ans+=query(L,R,m+1,r,rt<<1|1);
    return ans;
}

线段树区间合并类的做法

例题hdu1540

#include <bits/stdc++.h>
using namespace std;
int n,m;
#define maxx 50010
struct node
{
    int l,r,ls,rs,ms;//ls是左端最长连续1区间,rs是右端最长连续1区间,ms是l-r区间内最长连续1区间
}sum[maxx<<2];
void pushup(int rt)
{
    sum[rt].ls=sum[rt<<1].ls;//首先用子树的ls,rs更新根结点的
    sum[rt].rs=sum[rt<<1|1].rs;
    sum[rt].ms=max(max(sum[rt<<1].ms,sum[rt<<1|1].ms),sum[rt<<1].rs+sum[rt<<1|1].ls);//利用左右子树的ls,rs,ms求根的ms。
    //下面的代码和上面的不能互换位置
    if(sum[rt<<1].ls==sum[rt<<1].r-sum[rt<<1].l+1){//如果左子树满了,则要加上右子树的左边区间,因为左右子树管辖的区间是相邻的
        sum[rt].ls+=sum[rt<<1|1].ls;//更新这个是为了更新比rt更上层的结点
    }
    if(sum[rt<<1|1].rs==sum[rt<<1|1].r-sum[rt<<1|1].l+1){//理同上
        sum[rt].rs+=sum[rt<<1].rs;
    }
}
void buildtree(int l,int r,int rt)
{
    sum[rt].l=l;
    sum[rt].r=r;
    sum[rt].ls=sum[rt].rs=sum[rt].ms=r-l+1;
    if(l!=r){
        int mid=(l+r)>>1;
        buildtree(l,mid,rt<<1);
        buildtree(mid+1,r,rt<<1|1);
    }
}
void update(int rt,int num,int x)
{
    if(sum[rt].l==sum[rt].r){
        if(x==1){
            sum[rt].ls=sum[rt].rs=sum[rt].ms=1;
        }
        else{
            sum[rt].ls=sum[rt].rs=sum[rt].ms=0;
        }
        return ;
    }
    int mid=(sum[rt].l+sum[rt].r)>>1;
    if(num<=mid){
        update(rt<<1,num,x);
    }
    else{
        update(rt<<1|1,num,x);
    }
    pushup(rt);
}
int query(int rt,int num)
{
    if(sum[rt].l==sum[rt].r||sum[rt].ms==0||sum[rt].ms==sum[rt].r-sum[rt].l+1){
        return sum[rt].ms;
    }
    int mid=(sum[rt].r+sum[rt].l)>>1;
    if(num<=mid){//在左子树
        if(num>=sum[rt<<1].r-sum[rt<<1].rs+1){//如果在左子树的右区间,那么就要再查询右子树的左区间有多长了,也是因为这两个区间是相邻的
            return query(rt<<1,num)+query(rt<<1|1,mid+1);
        }
        else {
            return query(rt<<1,num);//没有进入右区间,那只在左子树的查询就好
        }
    }
    else {
        if(num<=sum[rt<<1|1].ls+sum[rt<<1|1].l-1){
            return query(rt<<1|1,num)+query(rt<<1,mid);
        }
        else return query(rt<<1|1,num);
    }
}
int main()
{
    while(scanf("%d %d",&n,&m)!=EOF){
    char op;
    int x;
    stack<int> s;
    buildtree(1,n,1);
    for(int i=1;i<=m;i++)
    {
        getchar();
        scanf("%c",&op);
        if(op=='D'){
            scanf("%d",&x);
            s.push(x);
            update(1,x,0);
        }
        else if(op=='R'){
            int k=s.top();
            s.pop();
            update(1,k,1);
        }
        else if(op=='Q'){
            scanf("%d",&x);
            printf("%d\n",query(1,x));
        }
    }
    }
    //system("pause");
    return 0;
}

POJ3667

//#include <bits/stdc++.h>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
int n,m;
#define maxx 50010
struct node
{
    int l,r,ls,rs,ms;//ls是左端最长连续1区间,rs是右端最长连续1区间,ms是l-r区间内最长连续1区间
    int lazy;
}sum[maxx<<2];
void pushup(int rt)
{
    sum[rt].ls=sum[rt<<1].ls;//首先用子树的ls,rs更新根结点的
    sum[rt].rs=sum[rt<<1|1].rs;
    sum[rt].ms=max(max(sum[rt<<1].ms,sum[rt<<1|1].ms),sum[rt<<1].rs+sum[rt<<1|1].ls);//利用左右子树的ls,rs,ms求根的ms。
    //下面的代码和上面的不能互换位置
    if(sum[rt<<1].ls==sum[rt<<1].r-sum[rt<<1].l+1){//如果左子树满了,则要加上右子树的左边区间,因为左右子树管辖的区间是相邻的
        sum[rt].ls+=sum[rt<<1|1].ls;//更新这个是为了更新比rt更上层的结点
    }
    if(sum[rt<<1|1].rs==sum[rt<<1|1].r-sum[rt<<1|1].l+1){//理同上
        sum[rt].rs+=sum[rt<<1].rs;
    }
}
void pushdown(int rt,int k)
{
    if(sum[rt].lazy!=-1)
    {
        sum[rt<<1].lazy=sum[rt<<1|1].lazy=sum[rt].lazy;
        sum[rt<<1|1].ms=sum[rt<<1|1].ls=sum[rt<<1|1].rs=sum[rt].lazy?0:(k>>1);
        sum[rt<<1].ms=sum[rt<<1].rs=sum[rt<<1].ls=sum[rt].lazy?0:k-(k>>1);
        sum[rt].lazy=-1;
    }
}
void buildtree(int l,int r,int rt)
{
    sum[rt].l=l;
    sum[rt].r=r;
    sum[rt].ls=sum[rt].rs=sum[rt].ms=r-l+1;
    sum[rt].lazy=-1;
    if(l!=r){
        int mid=(l+r)>>1;
        buildtree(l,mid,rt<<1);
        buildtree(mid+1,r,rt<<1|1);
    }
}
void update(int rt,int L,int R,int va)
{
    if(sum[rt].l>=L&&sum[rt].r<=R)
    {
        sum[rt].ls=sum[rt].rs=sum[rt].ms=va?0:sum[rt].r-sum[rt].l+1;
        sum[rt].lazy=va;
        return;
    }
    pushdown(rt,sum[rt].r-sum[rt].l+1);
    int mid=(sum[rt].l+sum[rt].r)>>1;
    if(mid>=L) update(rt<<1,L,R,va);
    if(mid<R) update(rt<<1|1,L,R,va);
    pushup(rt);
}
int query(int rt,int num)
{
    if(sum[rt].l==sum[rt].r)
    {
        return sum[rt].l;
    }
    pushdown(rt,sum[rt].r-sum[rt].l+1);
    int mid=(sum[rt].l+sum[rt].r)>>1;
    if(sum[rt<<1].ms>=num)
    {
        return query(rt<<1,num);
    }
    else if(sum[rt<<1].rs+sum[rt<<1|1].ls>=num)
    {
        return mid-sum[rt<<1].rs+1;
    }
    else return query(rt<<1|1,num);
}
int main()
{
    int N,M;
    scanf("%d %d",&N,&M);
    buildtree(1,N,1);
    for(int i=1;i<=M;i++)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int u;
            scanf("%d",&u);
            if(sum[1].ms<u)
            {
                printf("0\n");
            }
            else
            {
                int pos=query(1,u);
                update(1,pos,pos+u-1,1);
                printf("%d\n",pos);
            }
        }
        else
        {
            int u,v;
            scanf("%d %d",&u,&v);
            update(1,u,u+v-1,0);
        }
    }
    return 0;
}

维护区间最值

POJ3264

//#include <bits/stdc++.h>
#include <cstdio>
#include <algorithm>

using namespace std ;
#define maxn 50010
int N,Q;
int a[maxn];
struct node
{
    int l;
    int r;
    int v;
    int maxV;
    int minV;
}sum[maxn<<2];
void pushup(int rt)
{
    sum[rt].maxV=max(sum[rt<<1].maxV,sum[rt<<1|1].maxV);
    sum[rt].minV=min(sum[rt<<1].minV,sum[rt<<1|1].minV);
}

void buildtree(int rt,int l,int r)
{
    sum[rt].l=l;
    sum[rt].r=r;
    sum[rt].v=0;
    sum[rt].maxV=0;
    sum[rt].minV=0x3f3f3f3f;
    if(l!=r){
        int mid=(l+r)>>1;
        buildtree(rt<<1,l,mid);
        buildtree(rt<<1|1,mid+1,r);
    }
}

void update(int rt,int num,int value)
{
    if(sum[rt].l==sum[rt].r){
        sum[rt].v=value;
        sum[rt].maxV=sum[rt].minV=value;
        return ;
    }
    int mid=(sum[rt].l+sum[rt].r)>>1;
    if(num<=mid){
        update(rt<<1,num,value);
    }
    else update(rt<<1|1,num,value);
    pushup(rt);
}

int querymax(int rt,int L,int R)
{
    if(sum[rt].l>=L&&sum[rt].r<=R){
        return sum[rt].maxV;
    }
    if(sum[rt].l==sum[rt].r) return sum[rt].maxV;
    int mid=(sum[rt].l+sum[rt].r)>>1;
    int maxans=0;
    if(mid>=L)  {maxans=querymax(rt<<1,L,R);}
    if(mid<R) {maxans=max(maxans,querymax(rt<<1|1,L,R));}
    return maxans;
}

int querymin(int rt,int L,int R)
{
    if(sum[rt].l>=L&&sum[rt].r<=R){
        return sum[rt].minV;
    }
    if(sum[rt].l==sum[rt].r) return sum[rt].minV;
    int mid=(sum[rt].r+sum[rt].l)>>1;
    int minans=0x3f3f3f3f;
    if(mid>=L){
        minans=min(minans,querymin(rt<<1,L,R));
    }
    if(mid<R) {
        minans=min(minans,querymin(rt<<1|1,L,R));
    }
    return minans;
}
int main()
{
    scanf("%d %d",&N,&Q);
    buildtree(1,1,N);
    for(int i=1;i<=N;i++){
        scanf("%d",&a[i]);
        update(1,i,a[i]);
    }
    int x,y;
    for(int i=1;i<=Q;i++){
        scanf("%d %d",&x,&y);
        int mx=querymax(1,x,y);
        int mi=querymin(1,x,y);
        //printf("%d %d\n",mx,mi);
        printf("%d\n",mx-mi);
    }
    //system("pause");
    return 0;
}

按树的时间戳建立线段树

题 hdu3974(有区间修改,懒惰标记)

#include <bits/stdc++.h>
using namespace std;
#define maxn 50010
typedef long long ll;
struct node
{
    int l,r;
    ll task ,lz;    
}sum[maxn<<2];
int L[maxn],R[maxn];
vector<int> b[maxn];
int N,M;
int fa[maxn];
int cnt;
void dfs(int u)//通过深搜的时间戳确定每个点的管辖范围
{
    L[u]=++cnt;
    for(auto &it: b[u]){
        dfs(it);
    }
    R[u]=cnt;
}
void pushdown(int rt)
{
    if(sum[rt].lz!=-1){
        sum[rt<<1].lz=sum[rt].lz;
        sum[rt<<1|1].lz=sum[rt].lz;
        sum[rt<<1].task=sum[rt<<1|1].task=sum[rt].task;
        sum[rt].lz=-1;
    }
}
void buildtree(int rt,int l,int r)
{
    sum[rt].l=l;
    sum[rt].r=r;
    sum[rt].task=-1;
    sum[rt].lz=-1;
    if(l==r){
        return ;
    }
    else {
        int mid=(l+r)>>1;
        buildtree(rt<<1,l,mid);
        buildtree(rt<<1|1,mid+1,r);
    }
}
void update(int rt,ll t,int L,int R)
{
    if(sum[rt].l>=L&&sum[rt].r<=R){
        sum[rt].task=t;
        sum[rt].lz=t;
        return ;
    }
    pushdown(rt);
    int mid=(sum[rt].l+sum[rt].r)>>1;
    if(mid>=L){
        update(rt<<1,t,L,R);
    }
    if(mid<R){
        update(rt<<1|1,t,L,R);
    }
}
ll query(int rt,int s)
{
    if(sum[rt].l==sum[rt].r){
        return sum[rt].task;
    }
    pushdown(rt);
    int mid=(sum[rt].l+sum[rt].r)>>1;
    if(mid>=s){
        return query(rt<<1,s);
    }
    else return query(rt<<1|1,s);
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int e=1;e<=T;e++){
        scanf("%d",&N);
        int u,v;
        for(int i=1;i<=N;i++){
            fa[i]=i;
            b[i].clear();
        }
        for(int i=1;i<N;i++){
            scanf("%d %d",&u,&v);
            fa[u]=v;
            b[v].push_back(u);
        }
        cnt=0;
        for(int i=1;i<=N;i++){
            if(fa[i]==i){
                dfs(i);
                break;
            }
        }
        buildtree(1,1,N);
        scanf("%d",&M);
        printf("Case #%d:\n",e);
        char op;
        int x;
        ll y;
        for(int i=1;i<=M;i++){
            getchar();
            scanf("%c",&op);
            if(op=='T'){
              scanf("%d %lld",&x,&y);
                update(1,y,L[x],R[x]);//根据管辖范围插入任务值
            }
            else {
                scanf("%d",&x);
                printf("%lld\n",query(1,L[x]));
            }
        }
    }
    //system("pause");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值