這裏使用了zkw線段樹;
使標記永久化,並維護sum數組:僅考慮子樹的區間和;
這樣一個節點對答案的貢獻就是子樹和加上上方祖先的標記和;
代碼中L,R數組均可省去(但由於筆者太懶。。。。。。)
這樣就給出了一個與論文中不太一樣的sb方法,但各種複雜度還是一樣的;
#include<cstdio>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define rep2(i,k,n) for(int i=k;i>=n;i--)
using namespace std;
typedef long long ll;
void sc(ll& x){ll f=1;x=0;
char c=getchar();while(c>'9' || c<'0'){if(c=='-')f=-f;c=getchar();}
for(;c>='0' && c<='9';c=getchar())x=x*10+c-'0';
x*=f;
}
void sc(int& x){int f=1;x=0;
char c=getchar();while(c>'9' || c<'0'){if(c=='-')f=-f;c=getchar();}
for(;c>='0' && c<='9';c=getchar())x=x*10+c-'0';
x*=f;
}
typedef long long ll;
const int N=2e5+7;
ll v[N],sum[N<<1],dt[N<<1],L[N<<1],R[N<<1];
int M,n,m;
void build(){
for(M=1;M<=n;M<<=1);
rep(i,1,n)sum[M+i]=v[i];
rep(i,1,M)L[M+i]=R[M+i]=i;
rep2(i,M-1,1)sum[i]=sum[i<<1]+sum[i<<1|1],L[i]=L[i<<1],R[i]=R[i<<1|1];
}
inline void up(int x){if(x)sum[x]=sum[x<<1]+sum[x<<1|1]+(R[x]-L[x]+1)*dt[x];}
void Add(int s,int t,ll a){
if(s>t)return;
for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
if(~s&1)dt[s^1]+=a,sum[s^1]+=(R[s^1]-L[s^1]+1)*a;
if(t&1)dt[t^1]+=a,sum[t^1]+=(R[t^1]-L[t^1]+1)*a;
up(s>>1),up(t>>1);
}for(;s;s>>=1)up(s);
}
ll query(int s,int t){int l=s,r=t;
if(s>t)return 0;
ll res=0;
for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){
if(~s&1)res+=sum[s^1];
if(t&1)res+=sum[t^1];
if(l<=R[s>>1])res+=(R[s>>1]-l+1)*dt[s>>1];
if(r>=L[t>>1])res+=(r-L[t>>1]+1)*dt[t>>1];
}
for(s>>=1;s;s>>=1)res+=(r-l+1)*dt[s];
return res;
}int main(){
sc(n),sc(m);
rep(i,1,n)sc(v[i]);
build();
char s[20];int l,r;ll a;
rep(i,1,m){
scanf("%s",s);
if(s[0]=='C'){sc(l),sc(r),sc(a);Add(l,r,a);}
else {sc(l),sc(r);printf("%I64d\n",query(l,r));
}
}
}