LOJ6109
题目描述
题解
操作1,3都非常常见。
主要是操作2较难实现,其实仔细想想发现和平衡树的操作很像,删除一段,插入一段。由于是插入原来的一段序列,于是可持久化一下即可。本题解用的是可持久化FHQ,比较好写,但是空间常数较大。
非旋Treap的可持久化和线段树差不多,只要有修改的地方拉一个新点起来就行了。
代码
#include<bits/stdc++.h>
#define LL long long
#define M 30000009
using namespace std;
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int son[M][2],siz[M],tot,n,m,rt;
LL sum[M],val[M],tag[M];
int Rand(){return rand()|(rand()<<15);}
int build(int x){
val[++tot]=x,siz[tot]=1,sum[tot]=x;
return tot;
}
void pushup(int x){
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];
}
int copy(int k){
int p=++tot;
son[p][0]=son[k][0],son[p][1]=son[k][1];
siz[p]=siz[k],sum[p]=sum[k],val[p]=val[k],tag[p]=tag[k];
return p;
}
void add(int k,int v){tag[k]+=v,val[k]+=v,sum[k]+=siz[k]*v;}
void pushdown(int k){
if(tag[k]){
if(son[k][0]) son[k][0]=copy(son[k][0]),add(son[k][0],tag[k]);
if(son[k][1]) son[k][1]=copy(son[k][1]),add(son[k][1],tag[k]);
}tag[k]=0;
}
int merge(int a,int b){
int p;
if(!a||!b) return copy(a|b);
if(Rand()%(siz[a]+siz[b])<siz[a]) p=copy(a),pushdown(p),son[p][1]=merge(son[p][1],b);
else p=copy(b),pushdown(p),son[p][0]=merge(a,son[p][0]);
pushup(p);return p;
}
void split(int k,int &a,int &b,int v){
if(!k){a=b=0;return;}
pushdown(k);
if(siz[son[k][0]]>=v) b=copy(k),split(son[b][0],a,son[b][0],v),pushup(b);
else a=copy(k),split(son[a][1],son[a][1],b,v-siz[son[a][0]]-1),pushup(a);
}
void update(int l,int r,int v){
int a,b,c,d;
split(rt,a,b,r),split(a,c,d,l-1);
add(d,v),rt=merge(merge(c,d),b);
}
void query(int l,int r){
int a,b,c,d;
split(rt,a,b,r),split(a,c,d,l-1);
printf("%lld\n",sum[d]),rt=merge(merge(c,d),b);
}
void change(int l,int r,int ql,int qr){
int a,b,c,d,x,y,z,w;
split(rt,a,b,r),split(a,c,d,l-1),split(rt,x,y,qr),split(x,z,w,ql-1);
rt=merge(merge(z,copy(d)),y);
}
signed main(){
//freopen("add1.in","r",stdin);
//freopen("1.out","w",stdout);
srand(time(0));
n=read(),m=read();
for(int i=1;i<=n;i++) rt=merge(rt,build(read()));
for(int i=1;i<=m;i++){
int opt=read(),l=read(),r=read(),x=0;
if(opt==1) update(l,r,read());
if(opt==2) x=read(),change(l,l+x,r,r+x);
if(opt==3) query(l,r);
}return 0;
}