题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/4259.html
每年有两种操作,一是询问[L,R]内的土地这些年来的总产量,二是为[L,R]内的每一块地的年产量加1。
思路:假设X[i]表示一块土地第X[i]年增加年产量,则若询问年为y,总共更新了z次操作,那么这些年来的总产量为:
若将y看为第z+1次更新操作的话,
那么我们只需要用线段树维护两个东西,一个是区间加1操作,另一个是区间更新的总年份和。
而前面的b数组只需要一个前缀和就行。
#include
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
ll lazy1[maxn<<2|1],lazy2[maxn<<2|1];
//年产量增量和,更新年份和;
ll sum1[maxn<<2|1],sum2[maxn<<2|1];
void pushdown(int l,int r,int k){
int mid=(l+r)>>1;
if(lazy1[k]){
lazy1[k<<1]+=lazy1[k];
lazy1[k<<1|1]+=lazy1[k];
sum1[k<<1]+=lazy1[k]*(mid-l+1);
sum1[k<<1|1]+=lazy1[k]*(r-mid);
lazy1[k]=0;
}
if(lazy2[k]){
lazy2[k<<1]+=lazy2[k];
lazy2[k<<1|1]+=lazy2[k];
sum2[k<<1]+=lazy2[k]*(mid-l+1);
sum2[k<<1|1]+=lazy2[k]*(r-mid);
lazy2[k]=0;
}
}
void pushup(int k){
sum1[k]=sum1[k<<1]+sum1[k<<1|1];
sum2[k]=sum2[k<<1]+sum2[k<<1|1];
}
void build(){
memset(lazy1,0,sizeof(lazy1));
memset(lazy2,0,sizeof(lazy2));
memset(sum1,0,sizeof(sum1));
memset(sum2,0,sizeof(sum2));
}
void updata(int L,int R,int l,int r,int k,int y){
if(l>=L&&r<=R){
++lazy1[k];
sum1[k]+=(r-l+1);
lazy2[k]+=y;
sum2[k]+=(r-l+1)*y;
return ;
}
pushdown(l,r,k);
int mid=(l+r)>>1;
if(L<=mid) updata(L,R,l,mid,k<<1,y);
if(R>mid) updata(L,R,mid+1,r,k<<1|1,y);
pushup(k);
}
int thisy;
ll myfind(int L,int R,int l,int r,int k){
if(l>=L&&r<=R){
return sum1[k]*thisy-sum2[k];
}
pushdown(l,r,k);
ll res=0;
int mid=(l+r)>>1;
if(L<=mid) res+=myfind(L,R,l,mid,k<<1);
if(R>mid) res+=myfind(L,R,mid+1,r,k<<1|1);
pushup(k);
return res;
}
ll x[maxn];
char s[3];
int main(){
int n,m;
while(scanf("%d",&n)!=EOF){
int l,r;
bool f=1;
for(int i=1;i<=n;++i){
scanf("%lld",&x[i]);
x[i]+=x[i-1];
}
build();
scanf("%d",&m);
for(int i=1;i<=m;++i){
thisy=i;
scanf("%s%d%d",s,&l,&r);
if(s[0]=='Q'){
if(f) f=0;
else printf(" ");
printf("%lld",(x[r]-x[l-1])*i+myfind(l,r,1,n,1));
}
else{
updata(l,r,1,n,1,i);
}
}
printf("\n");
}
return 0;
}