题意:其实就是区间的加法和询问区间的和
解法:主要为了尝试一下splay维护区间和 因为之前只写过splay区间加法维护
然后觉得很神奇啊 左右两个节点是不算内的,以前写单点都没有发现这一点吧
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
#define ls ch[rt][0]
#define rs ch[rt][1]
#define rrs ch[root][1]
#define rls ch[root][0]
#define maxn 222222
int n,m;
int ch[maxn][2],fa[maxn],root,num[maxn],cnt;
ll sum[maxn],add[maxn],a[maxn],val[maxn];
inline void node(int rt){fa[rt]=sum[rt]=add[rt]=ls=rs=0;num[rt]=1;}
inline void up(int rt){
sum[rt]=val[rt]+sum[ls]+sum[rs];
num[rt]=num[ls]+num[rs]+1;
}
inline void down(int rt){
if(add[rt]){
if(ls)add[ls]+=add[rt],val[ls]+=add[rt],sum[ls]+=add[rt]*(num[ls]);
if(rs)add[rs]+=add[rt],val[rs]+=add[rt],sum[rs]+=add[rt]*(num[rs]);
add[rt]=0;
}
}
inline void rot(int rt){
int f=fa[rt],side=ch[f][1]==rt,ll=ch[rt][!side];
fa[ll]=f,ch[f][side]=ll;
fa[rt]=fa[f],ch[fa[f]][ch[fa[f]][1]==f]=rt;
fa[f]=rt,ch[rt][!side]=f;
up(f),up(rt);
}
void splay(int rt,int aim){
while(fa[rt]!=aim){
down(rt);
int f=fa[rt],ff=fa[f];
if(ff==aim)rot(rt);
else if((ch[f][1]==rt)==(ch[ff][1]==f))rot(f),rot(rt);
else rot(rt),rot(rt);
}if(!aim)root=rt;
}
inline void find(int tot,int sub){
int rt=sub;
while(1){
down(rt);
if(num[ls]+1==tot)break;
if(num[ls]>=tot)rt=ls;
else tot-=num[ls]+1,rt=rs;
}splay(rt,fa[sub]);
}
void _add(int l,int r,ll w){
find(l,root);find(r-l+2,rrs);
int rt=ch[rrs][0];
sum[rt]+=w*num[rt];add[rt]+=w;val[rt]+=w;
}
void build(int n){
cnt=0;node(0);num[0]=0;
node(++cnt);
for(int i=2;i<=n+1;++i){
node(++cnt);fa[i-1]=i;ch[i][0]=i-1;val[i]=a[i];up(i);
}root=cnt;
node(++cnt);fa[cnt]=cnt-1;ch[cnt-1][1]=cnt;up(root);
// for(int i=1;i<=n+2;++i)
// printf("%d %d %d %lld\n",i,fa[i],num[i],sum[i]);
}
char op[111];
int l,r;
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=2;i<=n+1;++i)scanf("%lld",&a[i]);
build(n);
while(m--){
scanf("%s%d%d",op,&l,&r);
if(*op=='Q'){
find(l,root);find(r-l+2,rrs);
// printf("%lld %lld\n",val[root],val[rrs]);
printf("%lld\n",sum[ch[rrs][0]]);
}else if(*op=='C'){
ll w;scanf("%lld",&w);
_add(l,r,w);
}
}
}
return 0;
}