LOJ6109-可持久化无旋Treap

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值