POJ 3468 A Simple Problem with Integers(区间更新)

来源:互联网 发布:不动点 知乎 编辑:程序博客网 时间:2024/05/16 18:13
A Simple Problem with Integers
Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu
Submit Status

Description

给出了一个序列,你需要处理如下两种询问。

"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。

"Q a b" 询问[a, b]区间中所有值的和。

Input

第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.

第二行包含n个整数,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。

接下来Q行询问,格式如题目描述。

线段是区间更新的裸题,来吧,学区间更新,前面我们学了线段树的点更新,比较好理解而且很好实现,但是当对一个区间进行操作的时候就不行,要对区间的每一个数进行修改会TLE,所以要学线段树的区间更新,首先现在结构体里面加上一个变量add,这是一个标记,标记的是当前节点所负责的区间进行的操作,我们只需要标记这个add并不需要传递。

首先来看建树,在建树时和普通的线段树一样,但是要对每一个节点的add标记置0。

void build(int id,int l,int r){    tree[id].l=l;    tree[id].r=r;    tree[id].add=0;    //标记置0    if(l==r)    {        tree[id].sum=a[l];        return ;    }    int mid=(l+r)/2;    build(id*2,l,mid);    build(id*2+1,mid+1,r);    tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;    //维护父节点的和值}
然后我们再来看查询函数,在查询函数,保证此节点负责的区间里面有需要查询的区间,如果此节点的区间完全在查询区间里面,就说明这个区间的sum是我们需要的,返回该值,如果此节点的区间中部分区间包涵查询区间,为了查询到正确值,我们在进行递归查询下一个节点时,需要将先在的节点中的add值向下传递,因为这个节点add包涵了要对这个区间的操作,并没有往下传递,如果我们要查询的区间在下层区间中,我们就必须向下传递来更新下层区间的值,这个向下传递为pushdown,在向下传递操作完成后,要对下层的两个节点的sum值进行维护,直接用add乘以下层节点区间的长度就能轻易维护本节点的sum值。
void pushdown(int id){    if(tree[id].add!=0)    {        tree[id*2].add+=tree[id].add;        tree[id*2+1].add+=tree[id].add;        long long lsum=tree[id*2].r-tree[id*2].l+1;        long long rsum=tree[id*2+1].r-tree[id*2+1].l+1;        tree[id*2].sum+=lsum*tree[id].add;           tree[id*2+1].sum+=rsum*tree[id].add;    //维护左右节点的sum值        tree[id].add=0;                          //标记清0    }}
long long querysum(int id,int ql,int qr){    int l=tree[id].l;    int r=tree[id].r;    int mid=(l+r)/2;    if(r<ql||l>qr)         //不在本区间内        return 0;    if(ql<=l&&qr>=r)         //本区间完全在查询区间里面        return tree[id].sum;    pushdown(id);                //将本节点的add向下传递    if(mid>=qr)        return querysum(id*2,ql,qr);    else if((mid+1)<=ql)        return querysum(id*2+1,ql,qr);    else        return querysum(id*2,ql,qr)+querysum(id*2+1,ql,qr);}

最后来看更新函数update,我们将一个要更新的区间按照mid,分为一个个小的要更新的区间,我们并不一定要走到叶子节点去更新节点的值,我们只需要更新能包涵更新区间的所有小区间的add值,有些区间我们可能并不会查询,然后我们把需要更新的节点进行pushdown往下更新。
void update(int id,int ql,int qr,int newval){    int l=tree[id].l;    int r=tree[id].r;    int mid=(l+r)/2;    if(r<ql||qr<l)         return;    if(ql<=l&&qr>=r)    {        tree[id].add+=newval;      //维护add        tree[id].sum+=(r-l+1)*newval;    //维护sum值        return ;    }    pushdown(id);     //更新add    if(mid>=qr)        update(id*2,ql,qr,newval);    else if((mid+1)<=ql)        update(id*2+1,ql,qr,newval);    else    {        update(id*2,ql,qr,newval);        update(id*2+1,ql,qr,newval);    }    tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;    //当下层节点都维护好过后再来维护父节点。}

最后附上完整代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define maxn 100005long long a[maxn];struct node{    int id;    int l;    int r;    long long sum;    long long add;}tree[maxn*4];void pushdown(int id){    if(tree[id].add!=0)    {        tree[id*2].add+=tree[id].add;        tree[id*2+1].add+=tree[id].add;        long long lsum=tree[id*2].r-tree[id*2].l+1;        long long rsum=tree[id*2+1].r-tree[id*2+1].l+1;        tree[id*2].sum+=lsum*tree[id].add;        tree[id*2+1].sum+=rsum*tree[id].add;        tree[id].add=0;    }}void update(int id,int ql,int qr,int newval){    int l=tree[id].l;    int r=tree[id].r;    int mid=(l+r)/2;    if(r<ql||qr<l)         return;    if(ql<=l&&qr>=r)    {        tree[id].add+=newval;        tree[id].sum+=(r-l+1)*newval;        return ;    }    pushdown(id);    if(mid>=qr)        update(id*2,ql,qr,newval);    else if((mid+1)<=ql)        update(id*2+1,ql,qr,newval);    else    {        update(id*2,ql,qr,newval);        update(id*2+1,ql,qr,newval);    }    tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;}long long querysum(int id,int ql,int qr){    int l=tree[id].l;    int r=tree[id].r;    int mid=(l+r)/2;    if(r<ql||l>qr)        return 0;    if(ql<=l&&qr>=r)        return tree[id].sum;    pushdown(id);    if(mid>=qr)        return querysum(id*2,ql,qr);    else if((mid+1)<=ql)        return querysum(id*2+1,ql,qr);    else        return querysum(id*2,ql,qr)+querysum(id*2+1,ql,qr);}void build(int id,int l,int r){    tree[id].l=l;    tree[id].r=r;    tree[id].add=0;    if(l==r)    {        tree[id].sum=a[l];        return ;    }    int mid=(l+r)/2;    build(id*2,l,mid);    build(id*2+1,mid+1,r);    tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;}int main(){    long long n,q;    char s[10];    scanf("%lld%lld",&n,&q);    for(int i=1;i<=n;i++)        scanf("%lld",&a[i]);    build(1,1,n);    while(q--)    {        long long c,b;        scanf("%s%lld%lld",s,&c,&b);        if(s[0]=='Q')        {            long long ans;            ans=querysum(1,c,b);            printf("%lld\n",ans);        }        else        {            long long k;            scanf("%lld",&k);            update(1,c,b,k);        }    }return 0;}




0 0
原创粉丝点击