題目鏈接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/C
題意:給定一個數組,然後動態修改某些區間的值,並詢問某些區間的和。
思路:既然是線段樹專題,那就用線段樹了。這是一個標準的線段樹維護動態區間和問題,很顯然,我們需要維護的是這些連續區間的和,當我們對某個子區間進行add操作時,必然會對這個子區間的上一個區間的和值產生影響,也就是說,対小區間的操作會對大區間的和值產生影響。所以當我們修改一個區間[a,b]的值時,還得修改他的上面的間的和值,但是,[a,b]和他下面的區間的和值就不用在去訪問了,我們可以再維護一個add值,表示每個區間的修改的值,這樣,在query時,在累加他上面的區間的add就行了(大區間的add包含對子區間add)。這樣一來,需要維護的變量就是add操作和sum值了。
代碼:
#include<iostream>
#include<cstdio>
#define LL long long
#define maxn 100010
using namespace std;
struct node{
int l,r;
LL s,w;//記錄該區間的和值,add操作
}T[maxn*3];
int N,Q,A[maxn];
LL build(int L,int R,int o){//初始化線段樹
T[o].l=L;T[o].r=R;T[o].w=0;
if(L==R) return T[o].s=A[L];
return T[o].s=build(L,(L+R)/2,o*2)+build((L+R)/2+1,R,o*2+1);
}
void add(int L,int R,int val,int o){
if(T[o].l==L && T[o].r==R){//注意這裏用的是==號
T[o].w+=val;return;//記錄該區間的add操作,但是可以不用更新該區間的和值
}
T[o].s+=(R-L+1)*val;//[L,R]一定是o對應區間的子區間,所以的更新o的和值
if(T[o].l==T[o].r) return;
if(L>=T[o*2+1].l) add(L,R,val,o*2+1);
else if(R<=T[o*2].r) add(L,R,val,o*2);
else{
add(L,T[o*2].r,val,o*2);add(T[o*2+1].l,R,val,o*2+1);
}
}
LL query(int L,int R,LL val,int o){
if(T[o].l>=L && T[o].r<=R) return T[o].s+(T[o].r-T[o].l+1)*(T[o].w+val);
if(T[o].l==T[o].r) return 0;
if(L>=T[o*2+1].l) return query(L,R,val+T[o].w,o*2+1);
if(R<=T[o*2].r) return query(L,R,val+T[o].w,o*2);
return query(L,T[o*2].r,val+T[o].w,o*2)+query(T[o*2+1].l,R,val+T[o].w,o*2+1);
}
int main(){
//freopen("D:\\in.txt","r",stdin);
while(cin>>N){
cin>>Q;
for(int i=1;i<=N;i++)
scanf("%d",A+i);
build(1,N,1);
int a,b,c;char ch;
while(Q--){
getchar();
scanf("%c",&ch);
if(ch=='Q'){
scanf("%d %d",&a,&b);
printf("%lld\n",query(a,b,0,1));
}else{
scanf("%d %d %d",&a,&b,&c);
add(a,b,c,1);
}
}
}
return 0;
}