/*
经典区间成段更新题目。
题意:给出一个长度n的数字序列,已经m个操作,*/
花了好些天研究ppt与别人的题解,不断的手动模拟才稍微理解lazy标记的熟络。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100005 #define LL __int64 struct node { int l,r; LL lazy,sum; //lazy为延迟标记 int Len() { return r-l+1; } int Mid() { return (l+r)>>1; } }tree[3*maxn]; int a[maxn]; void Lazy(int p) { if(tree[p].lazy) { tree[p<<1].lazy+=tree[p].lazy; tree[p<<1|1].lazy+=tree[p].lazy; tree[p<<1].sum+=tree[p<<1].Len()*tree[p].lazy; tree[p<<1|1].sum+=tree[p<<1|1].Len()*tree[p].lazy; tree[p].lazy=0; } } void BuildTree(int p,int l,int r) { tree[p].l=l,tree[p].r=r,tree[p].lazy=0; if(l==r) { tree[p].sum=a[l]; return ; } int mid=(l+r)>>1; BuildTree(p<<1,l,mid); BuildTree(p<<1|1,mid+1,r); tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum; } void change(int p,int l,int r,int x) { if(tree[p].l==l&&tree[p].r==r) { tree[p].lazy+=x; tree[p].sum+=x*tree[p].Len(); return; } Lazy(p); //标记下传 int mid=tree[p].Mid(); if(r<=mid) change(p<<1,l,r,x); else if(l>mid) change(p<<1|1,l,r,x); else { change(p<<1,l,mid,x); change(p<<1|1,mid+1,r,x); } tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum; } LL query(int p,int l,int r) { if(tree[p].l==l&&tree[p].r==r) return tree[p].sum; Lazy(p); int mid=tree[p].Mid(); if(r<=mid) return query(p<<1,l,r); else if(l>mid) return query(p<<1|1,l,r); else return query(p<<1,l,mid)+query(p<<1|1,mid+1,r); } int main() { int n,Q,l,r,x,i; char orde[3]; scanf("%d%d",&n,&Q); for(i=1;i<=n;i++) scanf("%d",&a[i]); BuildTree(1,1,n); while(Q--) { scanf("%s%d%d",orde,&l,&r); if(l>r) swap(l,r); if(orde[0]=='C') { scanf("%d",&x); change(1,l,r,x); } else printf("%I64d\n",query(1,l,r)); } return 0; }