题意:
"C a b c"means adding c to each of Aa, Aa+1, ... , Ab. -10000≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ..., Ab.
题解:
线段树模板题:区间add,区间sum。
区间add这里有必要说些pushdown函数的理解:
递归是从树根开始往下递归的,当进行区间add的时候,如果这个区间包含递归的当前区间,直接更新当前区间,并且标记上已经加的值,然后就返回了,不再对当前区间的子区间进行更新了,然后如果下次更新或者查询的时候,用到刚才那个区间的子区间了,就要对刚才的标记进行“下推”,对下面的子区间进行更新(+上刚才未加的)。
举个栗子:
区间[1,10],要对区间[1,7]进行区间+1,区间[1,10]左儿子为区间[1,5],包含于[1,7],所以直接对区间[1,5]进行+1*5(5个单点),并且做上标记。然后区间[1,5]下面的儿子并不进行更新,如果下次区间[1,3]要更新(+2)或者要查询[1,3]了,然后就把刚才的标记“下推”,并且更新(+1*3)。
这样做的目的就减少了好多次递归,如果区间[1,5]的子区间在以后没有更新操作的话,就无需管了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<vector>
#include<functional>
#include<utility>
#include<set>
#include<map>
#include<cmath>
#include<cctype>
#define INF 0x3f3f3f3fusing namespace std;const int maxn=100000+10;
typedef long long ll;
#define lson 2*i,l,m
#define rson 2*i+1,m+1,rll sum[maxn<<2];
ll addv[maxn<<2];void pushup(int i)
{sum[i]=sum[2*i]+sum[2*i+1];
}void build(int i,int l,int r)
{addv[i]=0;if(l==r){scanf("%I64d",&sum[i]);return;}int m=(l+r)/2;build(lson);build(rson);pushup(i);
}void pushdown(int i,int num)
{if(addv[i]){addv[2*i]+=addv[i];addv[2*i+1]+=addv[i];sum[2*i]+=addv[i]*(num-(num/2));sum[2*i+1]+=addv[i]*(num/2);addv[i]=0;}
}void update(int ql,int qr,int add,int i,int l,int r)
{if(ql<=l&&qr>=r){addv[i]+=add;sum[i]+=(ll)add*(r-l+1);return;}pushdown(i,r-l+1);int m=(l+r)/2;if(ql<=m)update(ql,qr,add,lson);if(m<qr)update(ql,qr,add,rson);pushup(i);
}ll query(int ql, int qr, int i, int l, int r)
{if(ql<=l&&qr>=r){return sum[i];}pushdown(i,r-l+1);int m=(l+r)/2;ll res=0;if(ql<=m)res+=query(ql,qr,lson);if(m<qr)res+=query(ql,qr,rson);return res;
}int main()
{int n,q;cin>>n>>q;build(1,1,n);while(q--){char s[10];scanf("%s",s);int x,y,z;if(s[0]=='Q'){scanf("%d%d",&x,&y);cout<<query(x,y,1,1,n)<<endl;}else{scanf("%d%d%d",&x,&y,&z);update(x,y,z,1,1,n);}}
}