POJ 3468

  一道线段树的区间修改题,以前写的线段树都是单点修改,这里用到了区间修改。我开始觉得单点修改和区间修改差不多,把区间内每个点进行一次单点修改就是区间修改了,这样虽是可行,但是时间复杂度却大大增加,想想看,一个点一个点地修改,这和暴力有什么区别呢。

  在网上找了好多资料,终于弄明白了用lazy-tag(lazy标记)进行区间修改。我的理解是这样的,为了减小修改次数,先将要进行的修改存起来,当访问到子节点的时候,如果发现父节点带有标记,就顺便将子节点更新,就像搭顺风车一样。在这道题中,每次可能要对一个区间加上一个值,比如全集为[1,7],现在要对区间[1,4]进行操作,例如要将[1,4]每个值都加1,如果采用单点更新,那么就要访问到叶节点一个一个第更新。实际上,当我们从[1,7]访问到它的左儿子[1,4]的时候,由于此时[1,4]恰好已经覆盖了要更新的区间,于是就将[1,4].tag+=1,当下次需要访问[1,4]的子节点时,发现[1,4]带有标记,就在访问[1,4]的子节点的时候顺便将以前记下的+1操作,对[1,4]的子节点进行实施,同时将[1,4]的子节点带上标记。

#include<stdio.h>
#include<string.h>
#define MAX_N 100005
struct node
{
    int left;
    int right;
    long long sum;//区间和
    long long tag;//标记,用来存储操作
}segTree[4*MAX_N];
void build(int,int,int);//建树
void update(int,int,int,int);//更新
void pushdown(int);//对子节点进行"秋后算账"
void pushup(int);//“算账”后,更新父节点
long long query(int,int,int);
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
    memset(segTree,0,sizeof(segTree));
    build(1,1,n);
    int i;
    for(i=1;i<=n;i++)
    {
        int num;
        scanf("%d",&num);
        update(1,i,i,num);
    }
    for(i=0;i<q;i++)
    {
        char ope[2];
        scanf("%s",ope);
        if(ope[0]=='C')
        {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        update(1,a,b,c);
        }
        else
        {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%lld\n",query(1,a,b));
        }
    }
    }
    return 0;
}
void build(int root,int le,int ri)
{
    segTree[root].left=le;
    segTree[root].right=ri;
    if(le==ri)
    return ;
    int mid=(le+ri)/2;
    build(root*2,le,mid);
    build(root*2+1,mid+1,ri);
}
void update(int root,int le,int ri,int val)
{
    if(le<=segTree[root].left&&ri>=segTree[root].right)
    {
    segTree[root].sum+=(segTree[root].right-segTree[root].left+1)*val;//算区间和
    segTree[root].tag+=val;//要用+=,因为可能要记多笔“帐”
    return ;
    }
    if(le>segTree[root].right||ri<segTree[root].left)
    {
        return ;
    }
    pushdown(root);//走到了这一步,说明要对root进行操作了,于是顺便对root的子节点进行算账了
    update(2*root,le,ri,val);
    update(2*root+1,le,ri,val);
    pushup(root);//更新一下root的sum
}
void pushdown(int root)
{
    if(segTree[root].tag)
    {
    segTree[2*root].tag+=segTree[root].tag;
        segTree[2*root].sum+=(segTree[2*root].right-segTree[2*root].left+1)*segTree[root].tag;
    segTree[2*root+1].tag+=segTree[root].tag;
    segTree[2*root+1].sum+=(segTree[2*root+1].right-segTree[2*root+1].left+1)*segTree[root].tag;
    segTree[root].tag=0;
    }
}
void pushup(int root)
{
    segTree[root].sum=segTree[2*root].sum+segTree[2*root+1].sum;
}
long long query(int root,int le,int ri)
{
    if(le<=segTree[root].left&&ri>=segTree[root].right)
    {
    return segTree[root].sum;
    }
      if(le>segTree[root].right||ri<segTree[root].left)
    {
        return 0;
    }
    pushdown(root);
    long long ans=0;
    ans+=query(2*root,le,ri);
    ans+=query(2*root+1,le,ri);
    return ans;
}
posted @ 2012-08-07 17:03  等待电子的砹  阅读(134)  评论(0)    收藏  举报