线段树的模板题!区间更新
区间更新的关键在于lazy标记,
如果要更新的区间包括当前的区间的话,就加对当前的这个区间加一个lazy标记,更新整个区间的值,并且停止,不再继续往下更新,
当再次更新到这个区间的时候,就是会用到这个这个区间的值的时候,
就把这个lazy标记释放掉(更新左子树和右子树,同时消除lazy标记)
这个题对区间的更新是同时对每个数字加上或减去同一个数字(c)
如果当前区间的左右端点分别是ls,rs的话,更新的话就是+(-)(rs-ls+1)*c;
# include <cstdio> # include <iostream> # include <cstring> # include <algorithm> using namespace std; const int maxn=1e5+5; long long int sum[maxn*4],seg[maxn*4]; void pushup(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; return ; } void pushdown(int l,int r,int rt){ int mid=(l+r)>>1; seg[rt<<1]+=seg[rt]; sum[rt<<1]+=(mid-l+1)*seg[rt]; seg[rt<<1|1]+=seg[rt]; sum[rt<<1|1]+=(r-mid)*seg[rt]; seg[rt]=0; } void build(int l,int r,int rt){ seg[rt]=0; if(l==r) { scanf("%lld",&sum[rt]); return ; } int mid=(l+r)>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); pushup(rt); } void update(int L,long long int R,int l,int r,int rt,int c){ if(L<=l&&r<=R) { seg[rt]+=c; sum[rt]+=(r-l+1)*c; return ; } if(seg[rt]) pushdown(l,r,rt); int mid=(l+r)>>1; if(L<=mid) update(L,R,l,mid,rt<<1,c); if(mid<R) update(L,R,mid+1,r,rt<<1|1,c); pushup(rt); } long long int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R){ return sum[rt]; } if(seg[rt]) pushdown(l,r,rt); int mid=(l+r)>>1; long long int ans=0; if(L<=mid) ans+=query(L,R,l,mid,rt<<1); if(mid<R) ans+=query(L,R,mid+1,r,rt<<1|1); pushup(rt); return ans; } int main(){ long long int n,q; while(scanf("%lld%lld",&n,&q)==2&&n&&q){ build(1,n,1); char s[5]; long long int a,b; int c; for(long long int i=0;i<q;i++){ scanf("%s",s); if(s[0]=='Q'){ scanf("%lld%lld",&a,&b); printf("%lld ",query(a,b,1,n,1)); } if(s[0]=='C'){ scanf("%lld%lld%d",&a,&b,&c); update(a,b,1,n,1,c); } } } return 0; }