传送门
之前用 FhqTreap 写过,刚刚学了 splay,再用 splay 写一下。
splay 比 FhqTreap 好的地方就是好写一点,但速度丢人。
splay 处理区间问题,就每次将代表 l-1 位置的点甩到根,然后将代表 r+1 的点甩到根的右儿子,那么此时 r+1 的点的左子树就是要处理的区间。
在指定位置插入数也是一个道理,将 pos-1 甩到根,pos 甩到根的右儿子,把新插入的点设为 pos 的左儿子即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,a[N];
struct Splay{
int root,siz[N],fa[N],ch[N][2],tot;LL sum[N],val[N],tag[N];
int newnode(int x,int f){fa[++tot]=f;val[tot]=sum[tot]=x;siz[tot]=1;return tot;}
int relat(int p,int f){return ch[f][1]==p;}
void connect(int p,int f,int k){ch[f][k]=p;fa[p]=f;}
void pushup(int p){
siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+1;
sum[p]=sum[ch[p][0]]+sum[ch[p][1]]+val[p];
}
void pushdown(int id){
int ls=ch[id][0],rs=ch[id][1];
sum[ls]+=tag[id]*siz[ls];val[ls]+=tag[id];tag[ls]+=tag[id];
sum[rs]+=tag[id]*siz[rs];val[rs]+=tag[id];tag[rs]+=tag[id];
tag[id]=0;
}
void rotate(int p){
int f=fa[p],ff=fa[f],k=relat(p,f);
connect(ch[p][k^1],f,k);
connect(p,ff,relat(f,ff));
connect(f,p,k^1);
pushup(f);pushup(p);
}
void splay(int p,int top){
if(top==0) root=p;
while(fa[p]!=top){
int f=fa[p],ff=fa[f];
if(ff!=top) relat(p,f)^relat(f,ff)?rotate(p):rotate(f);
rotate(p);
}
}
int findpos(int k){
int p=root;
while(1){
if(tag[p]) pushdown(p);
if(k<=siz[ch[p][0]]) p=ch[p][0];
else if(k==siz[ch[p][0]]+1) break;
else k-=siz[ch[p][0]]+1,p=ch[p][1];
}
return p;
}
void insert(int k,int x=0){
int p=findpos(k),q=findpos(k+1);
splay(p,0);splay(q,p);
int id=newnode(x,q);
ch[q][0]=id;
splay(id,0);
}
void upd(int l,int r,int x){
int p=findpos(l),q=findpos(r+2);
splay(p,0);splay(q,p);
int id=ch[q][0];
sum[id]+=1ll*x*siz[id];val[id]+=x;tag[id]+=x;
}
LL ask(int l,int r){
int p=findpos(l),q=findpos(r+2);
splay(p,0);splay(q,p);
return sum[ch[q][0]];
}
}spl;
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=0;i<=n+1;i++){
int p=spl.newnode(a[i],i);
if(i) spl.ch[i][1]=p;
spl.splay(p,0);
}
int m=read();
while(m--){
int opt=read();
if(opt==1) {int pos=read();spl.insert(pos);}
else if(opt==2){
int l=read(),r=read(),x=read();
spl.upd(l,r,x);
}
else if(opt==3){
int l=read(),r=read();
printf("%lld
",spl.ask(l,r));
}
}
return 0;
}