形形色色的线段树练习——codevs线段树练习1-5:线段树,树状数组及分块模板

来源:互联网 发布:淘宝滑动验证码 编辑:程序博客网 时间:2024/05/18 00:38

形形色色的线段树练习

线段树练习1

http://codevs.cn/problem/1080/

//线段树版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;int t,n,m,pos,a,b;ll value;int num[10000001];int ord;struct inte{    int l,r,sum,add;}tree[10000001];/*void pushdown(int now){    if(tree[now].add)    {        tree[now<<1].sum+=tree[now].add*(tree[now<<1].r-tree[now<<1].l+1);        tree[now<<1].add+=tree[now].add;        tree[now<<1|1].sum+=tree[now].add*(tree[now<<1|1].r-tree[now<<1|1].l+1);        tree[now<<1|1].add+=tree[now].add;        tree[now].add=0;//防止再次pushdown时重复下放     }}*/void update(int now){    tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;}void build(int now,int l,int r){    tree[now].l=l;    tree[now].r=r;    if(l==r)    {        tree[now].sum=num[l];        return;    }    int mid=(l+r)>>1;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    update(now);}void point_change(int now,int l,int r,int pos,ll value){    if(l==r)    {        tree[now].sum+=value;        return;    }    int mid=(l+r)>>1;    if(pos<=mid)    point_change(now<<1,l,mid,pos,value);    else    point_change(now<<1|1,mid+1,r,pos,value);    update(now);}ll ask(int now,int l,int r){    if(tree[now].l>=l&&r>=tree[now].r)    {        return tree[now].sum;    }    //pushdown(now);点修改无需标记下发     int mid=(tree[now].l+tree[now].r)>>1;    ll ans=0;    if(l<=mid)    {        ans+=ask(now<<1,l,r);    }    if(r>mid)    {        ans+=ask(now<<1|1,l,r);    }    return ans;}int main(){    scanf("%d",&n);    for(int j=1;j<=n;j++)    scanf("%d",&num[j]);    build(1,1,n);    scanf("%d",&m);    for(int i=1;i<=m;i++)    {           scanf("%d",&ord);        if(ord==1)        {            scanf("%d%d",&pos,&value);            point_change(1,1,n,pos,value);        }        if(ord==2)        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask(1,a,b));        }    }    return 0;}



//树状数组版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,m,p,a,b,value;int num[100010],c[100010];int lowbit(int x){    return x&(-x);}void add(int k,int value){    for(int i=k;i<=n;i+=lowbit(i))    c[i]+=value;}int sum(int l,int r){    int ans=0;    for(int i=r;i>0;i-=lowbit(i))    ans+=c[i];    for(int i=l-1;i>0;i-=lowbit(i))    ans-=c[i];    return ans;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        add(i,num[i]);    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&p);        if(p==1)        {            scanf("%d%d%d",&a,&b,&value);            for(int i=a;i<=b;i++)            add(i,value);        }        if(p==2)        {            scanf("%d",&a);            printf("%d\n",c[a]-sum(a-lowbit(a)+1,a-1));        }    }    return 0;}



//分块版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,m,a,b,p,size;int num[100010],pos[100010],sum[100010];void add(int x,int value){    num[x]+=value;    sum[pos[x]]+=value;}int count(int l,int r){    int ans=0;    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    ans+=num[i];    if(pos[l]^pos[r])    {        for(int i=r;pos[i]==pos[r];i--)        ans+=num[i];    }    for(int i=pos[l]+1;i<pos[r];i++)//sum存储修改后区间总值     ans+=sum[i];    return ans;}int main(){    scanf("%d",&n);    size=sqrt(n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        pos[i]=i/size;        sum[pos[i]]+=num[i];    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&p);        if(p==1)        {            scanf("%d%d",&a,&b);            add(a,b);        }        if(p==2)        {            scanf("%d%d",&a,&b);            printf("%d\n",count(a,b));        }    }    return 0;} 


线段树练习2

http://codevs.cn/problem/1081/

//线段树版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;int t,n,m,pos,a,b;ll value;int num[10000001];int ord;struct inte{    int l,r,sum,add;}tree[10000001];void pushdown(int now){    if(tree[now].add)    {        tree[now<<1].sum+=tree[now].add*(tree[now<<1].r-tree[now<<1].l+1);        tree[now<<1].add+=tree[now].add;        tree[now<<1|1].sum+=tree[now].add*(tree[now<<1|1].r-tree[now<<1|1].l+1);        tree[now<<1|1].add+=tree[now].add;        tree[now].add=0;    }}void update(int now){    tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;}void build(int now,int l,int r){    tree[now].l=l;    tree[now].r=r;    if(l==r)    {        tree[now].sum=num[l];        return;    }    int mid=(l+r)>>1;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    update(now);}void point_change(int now,int l,int r,int pos,int value){    if(l==r)    {        tree[now].sum+=value;        return;     }    int mid=(l+r)>>1;    if(pos<=mid)    {        point_change(now<<1,l,mid,pos,value);    }    if(pos>mid)    {        point_change(now<<1|1,mid+1,r,pos,value);    }    update(now);}void change(int now,int l,int r,ll value){    if(tree[now].l>=l&&tree[now].r<=r)    {        tree[now].sum+=(tree[now].r-tree[now].l+1)*value;        tree[now].add+=value;        return;    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    change(now<<1,l,r,value);    if(r>mid)    change(now<<1|1,l,r,value);    update(now);}ll ask(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    {        return tree[now].sum;    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    ll ans=0;    if(l<=mid)    {        ans+=ask(now<<1,l,r);    }    if(r>mid)    {        ans+=ask(now<<1|1,l,r);    }    return ans;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    scanf("%d",&num[i]);    build(1,1,n);    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&ord);        if(ord==1)        {            scanf("%d%d%lld",&a,&b,&value);            change(1,a,b,value);        }        if(ord==2)        {            scanf("%d",&a);            printf("%lld\n",ask(1,a,a));        }    }    return 0;}



//树状数组版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,m,p,a,b,value;int num[100010],c[100010];int lowbit(int x){    return x&(-x);}void add(int k,int value){    for(int i=k;i<=n;i+=lowbit(i))    c[i]+=value;}int sum(int l,int r){    int ans=0;    for(int i=r;i>0;i-=lowbit(i))    ans+=c[i];    for(int i=l-1;i>0;i-=lowbit(i))    ans-=c[i];    return ans;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        add(i,num[i]);    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&p);        if(p==1)        {            scanf("%d%d%d",&a,&b,&value);            for(int i=a;i<=b;i++)            add(i,value);        }        if(p==2)        {            scanf("%d",&a);            printf("%d\n",c[a]-sum(a-lowbit(a)+1,a-1));//左子树及自身的值之和-sum(左子树第一个元素,左子树最后一个元素)        }    }    return 0;}



//分块版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,m,a,b,p,size,value;int num[100010],pos[100010],ad[100010];void add(int l,int r,int value){    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    num[i]+=value;    if(pos[l]^pos[r])    {        for(int i=r;pos[i]==pos[r];i--)        num[i]+=value;    }    for(int i=pos[l]+1;i<pos[r];i++)//add存储区间修改量     ad[i]+=value;}int main(){    scanf("%d",&n);    size=sqrt(n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        pos[i]=i/size;    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&p);        if(p==1)        {            scanf("%d%d%d",&a,&b,&value);            add(a,b,value);        }        if(p==2)        {            scanf("%d",&a);            printf("%d\n",num[a]+ad[pos[a]]);        }    }    return 0;} 


线段树练习3

http://codevs.cn/problem/1082/

//线段树版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;int t,n,m,pos,a,b;ll value;int num[10000001];int ord;struct inte{    int l,r;    ll sum,add;//注意注意 }tree[10000001];void pushdown(int now){    if(tree[now].add)    {        tree[now<<1].sum+=tree[now].add*(tree[now<<1].r-tree[now<<1].l+1);        tree[now<<1].add+=tree[now].add;        tree[now<<1|1].sum+=tree[now].add*(tree[now<<1|1].r-tree[now<<1|1].l+1);        tree[now<<1|1].add+=tree[now].add;        tree[now].add=0;    }}void update(int now){    tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;}void build(int now,int l,int r){    tree[now].l=l;    tree[now].r=r;    if(l==r)    {        tree[now].sum=num[l];        return;    }    int mid=(l+r)>>1;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    update(now);}void point_change(int now,int l,int r,int pos,int value){    if(l==r)    {        tree[now].sum+=value;        return;     }    int mid=(l+r)>>1;    if(pos<=mid)    {        point_change(now<<1,l,mid,pos,value);    }    if(pos>mid)    {        point_change(now<<1|1,mid+1,r,pos,value);    }    update(now);}void change(int now,int l,int r,ll value){    if(tree[now].l>=l&&tree[now].r<=r)    {        tree[now].sum+=(tree[now].r-tree[now].l+1)*value;        tree[now].add+=value;        return;    }    int mid=(tree[now].l+tree[now].r)>>1;    pushdown(now);    if(l<=mid)    change(now<<1,l,r,value);    if(r>mid)    change(now<<1|1,l,r,value);    update(now);}ll ask(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    {        return tree[now].sum;    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    ll ans=0;    if(l<=mid)    {        ans+=ask(now<<1,l,r);    }    if(r>mid)    {        ans+=ask(now<<1|1,l,r);    }    return ans;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    scanf("%d",&num[i]);    build(1,1,n);    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&ord);        if(ord==1)        {            scanf("%d%d%lld",&a,&b,&value);            change(1,a,b,value);        }        if(ord==2)        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask(1,a,b));        }    }    return 0;}



//树状数组版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;ll n,m,p,a,b,value,sum1,sum2;ll num[200010],c1[200010],c2[200010];ll lowbit(ll x){    return x&(-x);}void add(ll r[],ll pos,ll value){    for(ll i=pos;i<=n;i+=lowbit(i))    r[i]+=value;}ll sigma(ll *r,ll pos){    ll ans=0;    for(ll i=pos;i>0;i-=lowbit(i))    ans+=r[i];    return ans;}int main(){    scanf("%lld",&n);    for(ll i=1;i<=n;i++)    {        scanf("%lld",&num[i]);        add(c1,i,num[i]-num[i-1]);        add(c2,i,(i-1)*(num[i]-num[i-1]));    }    scanf("%lld",&m);    for(ll i=1;i<=m;i++)    {        scanf("%lld",&p);        if(p==1)        {            scanf("%lld%lld%lld",&a,&b,&value);            add(c1,a,value);            add(c2,a,(a-1)*value);            add(c1,b+1,-value);            add(c2,b+1,b*(-value));        }        if(p==2)        {            scanf("%lld%lld",&a,&b);            sum1=(a-1)*sigma(c1,a-1)-sigma(c2,a-1);            sum2=b*sigma(c1,b)-sigma(c2,b);            printf("%lld\n",sum2-sum1);        }    }    return 0;}

这里对以上内容做一点介绍:
设原数组为num[n],差分数组c1[n],则c1[i]=num[i]-num[i-1],明显地,num[i]=sigma(c1,i),如果想要修改num[i]到num[j],只需令c1[i]+=v,c1[j+1]-=v即可.
区间修改时间复杂度O(logn)
观察式子:
num[1]+num[2]+…+num[n]
= (c1[1])+(c1[1]+c1[2])+…+(c1[1]+c1[2]+…+c1[n])
= n * c1[1]+(n-1) * c1[2]+…+c1[n]
= n * (c1[1]+c1[2]+…+c1[n]) - (0 * c1[1]+1 * c1[2]+…+(n-1) * c1[n])
维护一个数组c2[n],其中c2[i] = (i-1)*c1[i],每当修改c1的时候,就同步修改一下c2
上式
=n*sigma(c1,n) - sigma(c2,n)
区间和查询,时间复杂度O(logn)
学习借鉴自http://blog.csdn.net/fsahfgsadhsakndas/article/details/52650026十分感谢.

//分块版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll; int n,m,a,b,p,size,value;int num[200010],pos[200010];ll sum[200010],ad[200010];void add_1(int x,int value){    num[x]+=value;    sum[pos[x]]+=value;}void add(int l,int r,int value){    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    add_1(i,value);    if(pos[l]^pos[r])    {        for(int i=r;pos[i]==pos[r];i--)        add_1(i,value);    }    for(int i=pos[l]+1;i<pos[r];i++)    ad[i]+=value;}ll count(int l,int r){    ll ans=0;    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    ans+=num[i]+ad[pos[l]];    if(pos[l]^pos[r])    {        for(int i=r;pos[i]==pos[r];i--)        ans+=num[i]+ad[pos[r]];    }    for(int i=pos[l]+1;i<pos[r];i++)//sum存储非完整修改此区间后区间总值,ad存储区间修改值     ans+=sum[i]+ad[i]*size;    return ans;}int main(){    scanf("%d",&n);    size=sqrt(n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        pos[i]=i/size;        sum[pos[i]]+=num[i];    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d",&p);        if(p==1)        {            scanf("%d%d%d",&a,&b,&value);            add(a,b,value);        }        if(p==2)        {            scanf("%d%d",&a,&b);            printf("%lld\n",count(a,b));        }    }    return 0;}


后面的好像不能用树状数组做了…..

线段树练习4

http://codevs.cn/problem/4919/

//线段树版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;int n,m,a1,b1;int num[1000010],tmp[10],tnp[10];ll value;char p[10000];struct inte{    int l,r;    ll add;    ll c[10];}tree[1000010];void update(int now){    for(int i=0;i<7;i++)    tree[now].c[i]=tree[now<<1].c[i]+tree[now<<1|1].c[i];}void pushdown(int now){    if(tree[now].add)    {        for(int i=0;i<7;i++)        {            tmp[(i+tree[now].add)%7]=tree[now<<1].c[i];            tnp[(i+tree[now].add)%7]=tree[now<<1|1].c[i];        }        for(int i=0;i<7;i++)        {            tree[now<<1].c[i]=tmp[i];            tree[now<<1|1].c[i]=tnp[i];        }        tree[now<<1].add+=tree[now].add;//注意是add+=         tree[now<<1|1].add+=tree[now].add;        tree[now].add=0;    }}void build(int now,int l,int r){    tree[now].l=l;    tree[now].r=r;    if(l==r)    {        tree[now].c[num[l]%7]=1;        return;    }    int mid=(l+r)>>1;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    update(now);}void changes(int now,int l,int r,ll value){    if(tree[now].l>=l&&tree[now].r<=r)    {        int k=value%7;        for(int i=0;i<7;i++)        tmp[(i+k)%7]=tree[now].c[i];        for(int i=0;i<7;i++)        tree[now].c[i]=tmp[i];        tree[now].add+=k;        return;    }    int mid=(tree[now].l+tree[now].r)>>1;    pushdown(now);    if(l<=mid)    changes(now<<1,l,r,value);    if(r>mid)    changes(now<<1|1,l,r,value);    update(now);}ll ask(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    {        return tree[now].c[0];    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    ll ans=0;    if(l<=mid)    {        ans+=ask(now<<1,l,r);    }    if(r>mid)    {        ans+=ask(now<<1|1,l,r);    }    return ans;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    scanf("%d",&num[i]);    build(1,1,n);    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%s",&p);        if(p[0]=='a')        {            scanf("%d%d%lld",&a1,&b1,&value);            changes(1,a1,b1,value);        }        if(p[0]=='c')        {            scanf("%d%d",&a1,&b1);            printf("%lld\n",ask(1,a1,b1));        }    }    return 0;}


维护区间内%7余0-6的数字的个数即可

//分块版本#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,m,k,size,a,b,value;int pos[100100],cnt[350][100100],num[100100],sum[1000]; char c[1000];void add_1(int x,int value){    cnt[pos[x]][num[x]]--;    cnt[pos[x]][num[x]=(num[x]+value)%7]++;}void add(int l,int r,int value){    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    add_1(i,value);    if(pos[l]^pos[r])    {        for(int i=r;pos[i]==pos[r];i--)        add_1(i,value);    }    for(int i=pos[l]+1;i<pos[r];i++)    sum[i]+=value;}int count(int l,int r){    int ans=0,tmp;    for(int i=l,tmp=sum[pos[l]]%7;pos[i]==pos[l]&&i<=r;i++)    {        if((!num[i]&&!tmp)||num[i]+tmp==7)        ans++;    }    if(pos[l]^pos[r])    {        for(int i=r,tmp=sum[pos[r]]%7;pos[i]==pos[r];i--)        if((!num[i]&&!tmp)||num[i]+tmp==7)        ans++;    }    for(int i=pos[l]+1;i<pos[r];i++)    ans+=cnt[i][(7-(sum[i]%=7))^7?7-sum[i]:0];    return ans;}int main(){    scanf("%d",&n);    size=sqrt(n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        cnt[pos[i]=i/size][num[i]%=7]++;    }    for(int i=n+1;i<=n+size;i++)    pos[i]=i/size;    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%s",&c);        if(c[0]=='a')        {            scanf("%d%d%d",&a,&b,&value);            add(a,b,value%7);        }        if(c[0]=='c')        {            scanf("%d%d",&a,&b);            printf("%d\n",count(a,b));        }    }    return 0;}


线段树练习4 加强版

http://codevs.cn/problem/5037/

//这个只能用分块做了#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,m,k,size,a,b,value;int pos[200010+450],cnt[200100/450+10][200100],num[200100],sum[200100/450+10];//数据范围 char type;inline int read_1(){    int ret=0;    char ch=getchar();    while(ch<'0'||ch>'9')    ch=getchar();    while(ch>='0'&&ch<='9')    {        ret=ret*10+(ch-'0');        ch=getchar();    }    return ret;}inline char read_2(){    char ch=getchar();    while(ch<'a'||ch>'z')    ch=getchar();    return ch;}void add_1(int x,int value){    cnt[pos[x]][num[x]]--;//原来的位置数量减1     cnt[pos[x]][num[x]=(num[x]+value)%k]++;//新位置数量加1 }void add(int l,int r,int value){    for(int i=l;pos[i]==pos[l]&&i<=r;i++)//从l到从左往右第一个完整的区间     add_1(i,value);    if(pos[l]^pos[r])//l与r不在同一区间内     {        for(int i=r;pos[i]==pos[r];i--)//从r到从右往左第一个完整的区间         add_1(i,value);    }    for(int i=pos[l]+1;i<pos[r];i++)//中间完整区间修改值之和更新     sum[i]+=value;}int count(int l,int r){    int ans=0,tmp;    for(int i=l,tmp=sum[pos[l]]%k;pos[i]==pos[l]&&i<=r;i++)//从l到从左往右第一个完整区间的结果统计     {        if((!num[i]&&!tmp)||num[i]+tmp==k)//原本数字为k的倍数/改变后的数字为k的倍数         ans++;    }    if(pos[l]^pos[r])    {        for(int i=r,tmp=sum[pos[r]]%k;pos[i]==pos[r];i--)//从r到从右往左第一个完整区间的结果统计         if((!num[i]&&!tmp)||num[i]+tmp==k)        ans++;    }    for(int i=pos[l]+1;i<pos[r];i++)//中间完整区间     ans+=cnt[i][(k-(sum[i]%=k))^k?k-sum[i]:0];//若区间修改值为k的倍数则统计区间内数字中%k0的个数,否则统计区间内数字中加上修改值为k的倍数的个数     return ans;}int main(){    n=read_1();//数据间存在空格采用手读     m=read_1();    k=read_1();    size=sqrt(n);    for(int i=1;i<=n;i++)    {        scanf("%d",&num[i]);        cnt[pos[i]=i/size][num[i]%=k]++;    }    for(int i=n+1;i<=n+size;i++)    pos[i]=i/size;    for(int i=1;i<=m;i++)    {        type=read_2();        if(type=='a')        {            a=read_1();            b=read_1();            value=read_1()%k;            add(a,b,value);        }        if(type=='c')        {            a=read_1();            b=read_1();            printf("%d\n",count(a,b));        }    }    return 0;}


注释都写进程序里了.
学习借鉴自//http://blog.csdn.net/fsahfgsadhsakndas/article/details/54836031十分感谢.

线段树练习5

http://codevs.cn/problem/4927/

//线段树版本#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>using namespace std;typedef long long ll;int n,m,a,b;int num[1000010];ll value;char p[1000];struct inte{    int l,r;    ll sum,add,maxn,minx,set;    bool f;}tree[1000010];void pushdown(int now){    if(tree[now].f)    {        tree[now<<1].sum=tree[now].set*(tree[now<<1].r-tree[now<<1].l+1);        tree[now<<1|1].sum=tree[now].set*(tree[now<<1|1].r-tree[now<<1|1].l+1);        tree[now<<1].add=0;        tree[now<<1|1].add=0;        tree[now<<1].maxn=tree[now].set;        tree[now<<1|1].maxn=tree[now].set;        tree[now<<1].minx=tree[now].set;        tree[now<<1|1].minx=tree[now].set;        tree[now<<1].set=tree[now].set;        tree[now<<1|1].set=tree[now].set;        tree[now<<1].f=1;        tree[now<<1|1].f=1;        tree[now].f=0;    }    if(tree[now].add)    {        tree[now<<1].sum+=tree[now].add*(tree[now<<1].r-tree[now<<1].l+1);        tree[now<<1|1].sum+=tree[now].add*(tree[now<<1|1].r-tree[now<<1|1].l+1);        tree[now<<1].add+=tree[now].add;        tree[now<<1|1].add+=tree[now].add;        tree[now<<1].maxn+=tree[now].add;        tree[now<<1].minx+=tree[now].add;        tree[now<<1|1].maxn+=tree[now].add;        tree[now<<1|1].minx+=tree[now].add;        tree[now].add=0;    }}void update(int now){    tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;    tree[now].maxn=max(tree[now<<1].maxn,tree[now<<1|1].maxn);    tree[now].minx=min(tree[now<<1].minx,tree[now<<1|1].minx);}void build(int now,int l,int r){    tree[now].l=l;    tree[now].r=r;    if(l==r)    {        tree[now].sum=num[l];        tree[now].maxn=num[l];        tree[now].minx=num[l];        return;    }    int mid=(l+r)>>1;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    update(now);}void change(int now,int l,int r,ll value){    if(tree[now].l>=l&&tree[now].r<=r)    {        tree[now].sum+=value*(tree[now].r-tree[now].l+1);        tree[now].add+=value;        tree[now].maxn+=value;        tree[now].minx+=value;        return;    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    change(now<<1,l,r,value);    if(r>mid)    change(now<<1|1,l,r,value);    update(now);}void sets(int now,int l,int r,int value){    if(tree[now].l>=l&&tree[now].r<=r)    {        tree[now].sum=value*(tree[now].r-tree[now].l+1);        tree[now].add=0;        tree[now].maxn=value;        tree[now].minx=value;        tree[now].set=value;        tree[now].f=1;        return;    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    sets(now<<1,l,r,value);    if(r>mid)    sets(now<<1|1,l,r,value);    update(now);}ll  sums(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    {        return tree[now].sum;    }    pushdown(now);    ll ans=0;    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    ans+=sums(now<<1,l,r);    if(r>mid)    ans+=sums(now<<1|1,l,r);    return ans;}ll maxs(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    {        return tree[now].maxn;    }    pushdown(now);    ll ans=-1000000007;    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    ans=max(ans,maxs(now<<1,l,r));    if(r>mid)    ans=max(ans,maxs(now<<1|1,l,r));    return ans;}ll mins(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    {        return tree[now].minx;    }    pushdown(now);    ll ans=1000000007;    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    ans=min(ans,mins(now<<1,l,r));    if(r>mid)    ans=min(ans,mins(now<<1|1,l,r));    return ans;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    scanf("%d",&num[i]);    build(1,1,n);    for(int i=1;i<=m;i++)    {        scanf("%s",&p);        if(p[0]=='a')        {            scanf("%d%d%lld",&a,&b,&value);            change(1,a,b,value);        }        if(p[0]=='s'&&p[1]=='e')        {            scanf("%d%d%lld",&a,&b,&value);            sets(1,a,b,value);        }        if(p[0]=='s'&&p[1]=='u')        {            scanf("%d%d",&a,&b);            printf("%lld\n",sums(1,a,b));        }        if(p[0]=='m'&&p[1]=='a')        {            scanf("%d%d",&a,&b);            printf("%lld\n",maxs(1,a,b));        }        if(p[0]=='m'&&p[1]=='i')        {            scanf("%d%d",&a,&b);            printf("%lld\n",mins(1,a,b));        }    }    return 0;}


注意标记下发时set的优先级高于add

//分块版本RE'0//区间编号从0开始,第一个与最后一个区间的长度不定,O(n)预处理每个区间的左右端点#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;int n,m,k,size,a,b;ll value;int pos[100100];ll num[100100]; char c[1000];struct inte{    ll sum,add,sets,maxn,minx,ls,rs;//修改后区间和,增加值,赋值,最大值,最小值,左端点,右端点 }p[100100];void pushdown(int k)//存在set操作需标记下发 {    if(p[k].sets!=-1)     {        for(int i=p[k].ls;i<=p[k].rs&&i<=n;i++)        num[i]=p[k].sets;        p[k].add=0;        p[k].sets=-1;    }    if(p[k].add)    {        for(int i=p[k].ls;i<=p[k].rs&&i<=n;i++)        num[i]+=p[k].add;        p[k].add=0;    }}void add(int l,int r,ll value){    pushdown(pos[l]);    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    num[i]+=value;    p[pos[l]].sum=0;//区间和与极值必须重新计算     p[pos[l]].maxn=-1e9+7;    p[pos[l]].minx=1e9+7;    for(int i=p[pos[l]].ls;i<=p[pos[l]].rs;i++)//扫描区间确定区间和与极值     {        p[pos[l]].sum+=num[i];        p[pos[l]].maxn=max(p[pos[l]].maxn,num[i]);        p[pos[l]].minx=min(p[pos[l]].minx,num[i]);    }    if(pos[l]^pos[r])//若l与r位于不同区间     {        pushdown(pos[r]);        for(int i=r;pos[i]==pos[r];i--)        num[i]+=value;        p[pos[r]].sum=0;        p[pos[r]].maxn=-1e9+7;        p[pos[r]].minx=1e9+7;        for(int i=p[pos[r]].ls;i<=p[pos[r]].rs;i++)        {            p[pos[r]].sum+=num[i];            p[pos[r]].maxn=max(p[pos[r]].maxn,num[i]);            p[pos[r]].minx=min(p[pos[r]].minx,num[i]);        }    }    for(int i=pos[l]+1;i<pos[r];i++)    {        if(p[i].sets!=-1)//存在set标记则将value加于set上        p[i].sets+=value;        else p[i].add+=value;        p[i].sum+=value*size;        p[i].maxn+=value;        p[i].minx+=value;    }}void sets(int l,int r,ll value){    pushdown(pos[l]);    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    num[i]=value;    p[pos[l]].sum=0;    p[pos[l]].maxn=-1e9+7;    p[pos[l]].minx=1e9+7;    for(int i=p[pos[l]].ls;i<=p[pos[l]].rs;i++)    {        p[pos[l]].sum+=num[i];        p[pos[l]].maxn=max(p[pos[l]].maxn,num[i]);        p[pos[l]].minx=min(p[pos[l]].minx,num[i]);    }    if(pos[l]^pos[r])    {        pushdown(pos[r]);        for(int i=r;pos[i]==pos[r];i--)        num[i]=value;        p[pos[r]].sum=0;        p[pos[r]].maxn=-1e9+7;        p[pos[r]].minx=1e9+7;        for(int i=p[pos[r]].ls;i<=p[pos[r]].rs;i++)        {            p[pos[r]].sum+=num[i];            p[pos[r]].maxn=max(p[pos[r]].maxn,num[i]);            p[pos[r]].minx=min(p[pos[r]].minx,num[i]);        }    }    for(int i=pos[l]+1;i<pos[r];i++)    {        p[i].sum=value*size;        p[i].sets=value;        p[i].add=0;//将add及时清空         p[i].maxn=value;        p[i].minx=value;    }}ll ask_sum(int l,int r){    ll ans=0;    pushdown(pos[l]);    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    ans+=num[i];     if(pos[l]^pos[r])    {        pushdown(pos[r]);        for(int i=r;pos[i]==pos[r];i--)        ans+=num[i];    }    for(int i=pos[l]+1;i<pos[r];i++)    ans+=p[i].sum;    return ans;}ll ask_max(int l,int r){    ll ans=-1e9+7;    pushdown(pos[l]);    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    ans=max(ans,num[i]);        if(pos[l]^pos[r])    {        pushdown(pos[r]);        for(int i=r;pos[i]==pos[r];i--)        ans=max(ans,num[i]);    }    for(int i=pos[l]+1;i<pos[r];i++)    ans=max(ans,p[i].maxn);    return ans;}ll ask_min(int l,int r){    ll ans=1e9+7;    pushdown(pos[l]);    for(int i=l;pos[i]==pos[l]&&i<=r;i++)    ans=min(ans,num[i]);        if(pos[l]^pos[r])    {        pushdown(pos[r]);        for(int i=r;pos[i]==pos[r];i--)        ans=min(ans,num[i]);    }    for(int i=pos[l]+1;i<pos[r];i++)    ans=min(ans,p[i].minx);    return ans;}int main(){    scanf("%d%d",&n,&m);    size=sqrt(n);    for(int i=0;i<=500;i++)//初始化     {        p[i].maxn=-1e9+7;        p[i].minx=1e9+7;        p[i].sets=-1;//不可赋0,set存在清0操作,仍有风险错误(set可能存在赋-1操作,最好新开变量确定是否存在set操作,add同理)     }    for(int i=1;i<=n;i++)    {        scanf("%lld",&num[i]);        pos[i]=i/size;//从0开始         p[pos[i]].sum+=num[i];        p[pos[i]].maxn=max(p[pos[i]].maxn,num[i]);        p[pos[i]].minx=min(p[pos[i]].minx,num[i]);    }    p[pos[1]].ls=1;//处理每个区间左右端点     for(int i=2;i<=n;i++)    {        if(pos[i]!=pos[i-1])        {            p[pos[i-1]].rs=i-1;            p[pos[i]].ls=i;        }    }    p[pos[n]].rs=n;    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%s",&c);        if(c[1]=='d')        {            scanf("%d%d%lld",&a,&b,&value);            add(a,b,value);        }        if(c[1]=='e')        {            scanf("%d%d%lld",&a,&b,&value);            sets(a,b,value);        }        if(c[1]=='u')        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask_sum(a,b));        }        if(c[1]=='a')        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask_max(a,b));        }        if(c[1]=='i')        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask_min(a,b));        }    }    return 0;}



//分块版本RE'1//区间编号从1开始,每个区间长度为标准的√n,可直接计算区间左右端点位置#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;typedef long long ll;int n,m,k,size,a,b;ll value;int pos[100100];ll num[100100]; char c[1000];struct inte{    ll sum,add,sets,maxn,minx,ls,rs;//修改后区间和,增加值,赋值,最大值,最小值,左端点,右端点 }p[100100];void pushdown(int k){    if(p[k].sets!=-1)    {        for(int i=(k-1)*size+1;i<=min(k*size,n);i++)//可直接计算位置        num[i]=p[k].sets;        p[k].add=0;        p[k].sets=-1;    }    if(p[k].add)    {        for(int i=(k-1)*size+1;i<=min(k*size,n);i++)        num[i]+=p[k].add;        p[k].add=0;    }}void add(int l,int r,int value){    int k=pos[l];    pushdown(k);//下放l不完整区间    for(int i=l;i<=min(k*size,r);i++)    num[i]+=value;    p[k].sum=0;    p[k].maxn=-1e9+7;    p[k].minx=1e9+7;    for(int i=(k-1)*size+1;i<=min(k*size,n);i++)    {        p[k].sum+=num[i];        p[k].maxn=max(p[k].maxn,num[i]);        p[k].minx=min(p[k].minx,num[i]);    }    for(int i=pos[l]+1;i<pos[r];i++)//下放完整区间     {        if(p[i].sets!=-1)        p[i].sets+=value;        else p[i].add+=value;        p[i].sum+=value*size;        p[i].maxn+=value;        p[i].minx+=value;     }    if(pos[l]==pos[r])    return;    k=pos[r];    pushdown(k);//下放r不完整区间    for(int i=(k-1)*size+1;i<=r;i++)    num[i]+=value;    p[k].sum=0;    p[k].maxn=-1e9+7;    p[k].minx=1e9+7;    for(int i=(k-1)*size+1;i<=min(k*size,n);i++)    {        p[k].sum+=num[i];        p[k].maxn=max(p[k].maxn,num[i]);        p[k].minx=min(p[k].minx,num[i]);    }}void sets(int l,int r,int value){    int k=pos[l];    pushdown(k);    for(int i=l;i<=min(k*size,r);i++)    num[i]=value;    p[k].sum=0;    p[k].maxn=-1e9+7;    p[k].minx=1e9+7;    for(int i=(k-1)*size+1;i<=min(k*size,n);i++)    {        p[k].sum+=num[i];        p[k].maxn=max(p[k].maxn,num[i]);        p[k].minx=min(p[k].minx,num[i]);    }    for(int i=pos[l]+1;i<pos[r];i++)    {        p[i].sets=p[i].maxn=p[i].minx=value;        p[i].sum=value*size;        p[i].add=0;    }    if(pos[l]==pos[r])    return;    k=pos[r];    pushdown(k);    for(int i=(k-1)*size+1;i<=r;i++)    num[i]=value;    p[k].sum=0;    p[k].maxn=-1e9+7;    p[k].minx=1e9+7;    for(int i=(k-1)*size+1;i<=min(k*size,n);i++)    {        p[k].sum+=num[i];        p[k].maxn=max(p[k].maxn,num[i]);        p[k].minx=min(p[k].minx,num[i]);    }}ll ask_sum(int l,int r){    ll ans=0;    int k=pos[l];    pushdown(k);    for(int i=l;i<=min(k*size,r);i++)    ans+=num[i];    for(int i=pos[l]+1;i<pos[r];i++)    ans+=p[i].sum;    if(pos[l]==pos[r])    return ans;    k=pos[r];    pushdown(k);    for(int i=(k-1)*size+1;i<=r;i++)    ans+=num[i];    return ans;}ll ask_max(int l,int r){    ll ans=-1e9+7;    int k=pos[l];    pushdown(k);    for(int i=l;i<=min(k*size,r);i++)    ans=max(ans,num[i]);    for(int i=pos[l]+1;i<pos[r];i++)    ans=max(ans,p[i].maxn);    if(pos[l]==pos[r])    return ans;    k=pos[r];    pushdown(k);    for(int i=(k-1)*size+1;i<=r;i++)    ans=max(ans,num[i]);    return ans;}ll ask_min(int l,int r){    ll ans=1e9+7;    int k=pos[l];    pushdown(k);    for(int i=l;i<=min(k*size,r);i++)    ans=min(ans,num[i]);    for(int i=pos[l]+1;i<pos[r];i++)    ans=min(ans,p[i].minx);    if(pos[l]==pos[r]) return ans;    k=pos[r];    pushdown(k);    for(int i=(k-1)*size+1;i<=r;i++)    ans=min(ans,num[i]);    return ans;}int main(){    scanf("%d%d",&n,&m);    size=sqrt(n);    for(int i=1;i<=500;i++)//初始化     {        p[i].maxn=-1e9+7;        p[i].minx=1e9+7;        p[i].sets=-1;    }    for(int i=1;i<=n;i++)    {        scanf("%lld",&num[i]);        pos[i]=(i-1)/size+1;        p[pos[i]].sum+=num[i];        p[pos[i]].maxn=max(p[pos[i]].maxn,num[i]);        p[pos[i]].minx=min(p[pos[i]].minx,num[i]);    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%s",&c);        if(c[1]=='d')        {            scanf("%d%d%lld",&a,&b,&value);            add(a,b,value);        }        if(c[1]=='e')        {            scanf("%d%d%lld",&a,&b,&value);            sets(a,b,value);        }        if(c[1]=='u')        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask_sum(a,b));        }        if(c[1]=='a')        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask_max(a,b));        }        if(c[1]=='i')        {            scanf("%d%d",&a,&b);            printf("%lld\n",ask_min(a,b));        }    }    return 0;}


学习借鉴自//http://www.cnblogs.com/harden/p/6486594.html
第一篇博客完成,之后我会再配图的(然而并没有).

原创粉丝点击