线段树lazy标记2:覆盖赋值与加法修改混合
题目
Description
给定一个正整数序列A,要求支持以下操作
1): ADD a b c 表示在[a,b]上加上一个常数C。
2): COVER a b c 把[a,b]整体赋值为一个常数K。
3): QUERY a b 查询[a,b]的sum。
Input
第一行两个正整数n、m,n表示序列长度,m表示操作数
第二行n个正整数,第i表示A[i]的大小
接下来的m行,每行有且仅有一种操作,具体和题目描述一致
n,m<=100000
其他权值都<=50000
小心爆int
Output
对于每个询问操作,输出答案
Sample Input
10 10 17 18 16 12 13 7 13 6 11 20 QUERY 5 6 QUERY 2 7 ADD 1 6 13 QUERY 4 10 ADD 2 5 18 COVER 2 8 11 ADD 6 9 5 QUERY 8 8 ADD 6 9 18 QUERY 5 7
Sample Output
20 79 121 16 79
思路:
很明显,这题是一道区间修改的题目;
但是多了覆盖赋值;
博主蒟蒻 刚写的时候是分优先级的,还打了每一个时间是覆盖赋值先,还是加法修改先;
但是,我试了一下,wa了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
struct sbbb { ll l,r,v,f,ff,time; }a[1000001]; inline ll R(ll x) { return x*2+1; } inline ll L(ll x) { return x*2; } inline void doit(ll p) { a[p].v=a[L(p)].v+a[R(p)].v; } inline void build(ll p,ll l,ll r) { a[p].l=l;a[p].r=r; if(l==r) { a[p].v=aa[l]; return; } ll mid=(l+r)>>1; build(L(p),l,mid); build(R(p),mid+1,r); doit(p); } inline void fdo(ll p) { if(a[p].f) { ll x=a[p].f,tim=a[p].time; a[L(p)].v+=(a[L(p)].r-a[L(p)].l+1)*x; a[R(p)].v+=(a[R(p)].r-a[R(p)].l+1)*x; a[L(p)].f+=x; a[R(p)].f+=x; a[L(p)].time=tim; a[R(p)].time=tim; a[p].f=0; } } inline void ffdo(ll p) { if(a[p].ff) { ll d=a[p].ff,tim=a[p].time; a[L(p)].v=(a[L(p)].r-a[L(p)].l+1)*d; a[R(p)].v=(a[R(p)].r-a[R(p)].l+1)*d; a[L(p)].ff=d; a[R(p)].ff=d; a[L(p)].time=tim; a[R(p)].time=tim; a[p].ff=0; } } inline void push_down(ll p) { if(a[p].time==2) { ffdo(p); fdo(p); } else if(a[p].time==1) { fdo(p); ffdo(p); } } inline void change(ll p,ll l,ll r,ll x) { if(l<=a[p].l&&r>=a[p].r) { a[p].v+=(a[p].r-a[p].l+1)*x; a[p].f+=x; a[p].time=2; return; } push_down(p); ll mid=(a[p].l+a[p].r)>>1; if(l<=mid) change(L(p),l,r,x); if(r>mid) change(R(p),l,r,x); doit(p); } inline void cover(ll p,ll l,ll r,ll x) { if(l<=a[p].l&&r>=a[p].r) { a[p].v=(a[p].r-a[p].l+1)*x; a[p].ff=x; a[p].time=1; return; } push_down(p); ll mid=(a[p].l+a[p].r)>>1; if(l<=mid) cover(L(p),l,r,x); if(r>mid) cover(R(p),l,r,x); doit(p); }
所以,我想了一下,其实不需要考虑优先级,直接覆盖的时候把加法的lazy标记清零就好了;
当时我想复杂了,以为会有加法的lazy标记没有清零;
覆盖的lazy标记与加法的lazy标记是一起(一起不代表同时间)下传的;
所以只需要在覆盖的时候把加法的lazy标记清零就好了;
那么每一次下传的时候,是先加,还是先覆盖呢;
我们在每一次覆盖的时候把加法的lazy标记清零了;
所以下传时,如果加法没被清零,那么加法肯定是在覆盖之后的;
这样就ok了;
代码:
#include<bits/stdc++.h> typedef long long ll; using namespace std; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n,m,aa[500001]; struct sbbb { ll l,r,v,f,ff; }a[500001]; inline ll R(ll x)//计算x的右节点的编号 { return x*2+1; } inline ll L(ll x)//计算x的左节点的编号 { return x*2; } inline void doit(ll p)//区间维护 { a[p].v=a[L(p)].v+a[R(p)].v; } inline void build(ll p,ll l,ll r)//建树 { a[p].l=l;a[p].r=r; if(l==r) { a[p].v=aa[l]; return; } ll mid=(l+r)>>1; build(L(p),l,mid); build(R(p),mid+1,r); doit(p); } inline void fdo(ll p)//加法lazy标记下传 { if(a[p].f) { ll x=a[p].f; a[L(p)].v+=(a[L(p)].r-a[L(p)].l+1)*x; a[R(p)].v+=(a[R(p)].r-a[R(p)].l+1)*x; a[L(p)].f+=x; a[R(p)].f+=x; a[p].f=0; } } inline void ffdo(ll p)//覆盖的lazy标记下传 { if(a[p].ff) { ll d=a[p].ff; a[L(p)].v=(a[L(p)].r-a[L(p)].l+1)*d; a[R(p)].v=(a[R(p)].r-a[R(p)].l+1)*d; a[L(p)].ff=d; a[R(p)].ff=d; a[L(p)].f=0; a[R(p)].f=0; //覆盖的lazy标记与加法的lazy标记是一起(一起不代表同时间)下传的; //所以只需要在覆盖的时候把加法的lazy标记清零就好了; a[p].ff=0; } } inline void push_down(ll p) { ffdo(p); fdo(p); //我们在每一次覆盖的时候把加法的lazy标记清零了; //所以下传时,如果加法没被清零,那么加法肯定是在覆盖之后的; //就不需要考虑优先级了 } inline void change(ll p,ll l,ll r,ll x)//区间加法修改 { if(l<=a[p].l&&r>=a[p].r) { a[p].v+=(a[p].r-a[p].l+1)*x; a[p].f+=x; return; } push_down(p); ll mid=(a[p].l+a[p].r)>>1; if(l<=mid) change(L(p),l,r,x); if(r>mid) change(R(p),l,r,x); doit(p); } inline void cover(ll p,ll l,ll r,ll x)//区间覆盖 { if(l<=a[p].l&&r>=a[p].r) { a[p].v=(a[p].r-a[p].l+1)*x; a[p].ff=x; a[p].f=0;//每一次覆盖的时候把加法的lazy标记清零; return; } push_down(p); ll mid=(a[p].l+a[p].r)>>1; if(l<=mid) cover(L(p),l,r,x); if(r>mid) cover(R(p),l,r,x); doit(p); } inline ll findout(ll p,ll l,ll r)//查询 { if(l<=a[p].l&&r>=a[p].r) return a[p].v; push_down(p); ll mid=(a[p].l+a[p].r)>>1; ll sum=0; if(l<=mid) sum+=findout(L(p),l,r); if(r>mid) sum+=findout(R(p),l,r); return sum; } int main() { n=read();m=read(); for(ll i=1;i<=n;i++) aa[i]=read(); build(1,1,n);//冬眠假期刚刚建树,我还有点糊涂 for(ll i=1;i<=m;i++) { char c[5]; scanf("%s",c); ll x=read(),y=read(); if(c[0]=='Q') { ll ans=findout(1,x,y); printf("%lld\n",ans); } else if(c[0]=='A') { ll z=read(); change(1,x,y,z); } else { ll z=read(); cover(1,x,y,z); } } return 0;//恶意的return 0; }