可持久化无旋Treap学习

可持久化无旋Treap

今天又学习了可持久化非旋Treap,其实很简单,将普通的非旋Treap持久化一遍就行了。具体来说,就是将每次操作后得到的树记录下来,每次需要改变一个点的信息时,将原有的点的信息记录下来,建一个新点去更改它的信息。

其实持久化的过程与线段树的持久化相似。

其实打出来跟普通的非旋Treap差不多,加几个改点的步骤即可。

非旋Treap学习见此处:非旋Treap学习


模板

下面是模板。其实与非旋Treap差不多,可以跳过

分裂

void split(int now,int k,int &x,int &y){
	if(!now){
		x=y=0;
		return ;
	}
	if(k<val[now]){
		y=++tot;newpoint(y,now);
		split(son[y][0],k,x,son[y][0]);
		updata(y);
	}
	else{
		x=++tot;newpoint(x,now);
		split(son[x][1],k,son[x][1],y);
		updata(x);
	}
}

合并

int merge(int a,int b){
	if(!a||!b) return a+b;
	if(rnd[a]>rnd[b]){
		int p=++tot;newpoint(p,a);
		son[p][1]=merge(son[p][1],b);
		updata(p);return p;
	}	
	int p=++tot;newpoint(p,b);
	son[p][0]=merge(a,son[p][0]);
	updata(p);return p;
}

插入

void Insert(int &rt,int w){
	int xa=0,ya=0,z=0;split(rt,w,xa,ya);
	z=newnode(w);rt=merge(merge(xa,z),ya);
}

删除

void Delete(int &rt,int w){
	int xa=0,ya=0,z=0,xb=0,yb=0;
	split(rt,w,xa,ya);split(xa,w-1,xb,yb);
	rt=merge(merge(xb,son[yb][0]),merge(son[yb][1],ya));
}

查询排名

int rankth(int &rt,int w){
	int xa,ya;split(rt,w-1,xa,ya);
	int res=siz[xa]+1;rt=merge(xa,ya);
	return res;
}

查询第k小

int kth(int p,int w){
	if(w==siz[son[p][0]]+1) return val[p];
	if(w<=siz[son[p][0]]) return kth(son[p][0],w);
	return kth(son[p][1],w-siz[son[p][0]]-1);
}

前驱与后继

int pre(int &rt,int w){
	int xa,ya;split(rt,w-1,xa,ya);
	if(!xa) return -INF;
	int k=siz[xa],res=kth(xa,k);
	rt=merge(xa,ya);return res;
}
int nxt(int &rt,int w){
	int xa,ya;split(rt,w,xa,ya);
	if(!ya) return INF;
	int res=kth(ya,1);rt=merge(xa,ya);
	return res; 
}

例题

还是去看一看【模板】可持久化平衡树吧!

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MAXN 500005
using namespace std;
typedef long long LL;
const int INF=0x7f7f7f7f;
#define gc() getchar()
int son[MAXN*50][2],tot,rot[MAXN];
int rnd[MAXN*50],siz[MAXN*50],n;
int val[MAXN*50];
template<typename _T>
inline void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
} 
void updata(int x){
	siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}
int newnode(int x){
	int p=++tot;
	val[p]=x;siz[p]=1;rnd[p]=rand();
	son[p][0]=son[p][1]=0;updata(p);
	return p;
}
void newpoint(int a,int b){
	val[a]=val[b];siz[a]=siz[b];rnd[a]=rnd[b];
	son[a][0]=son[b][0];son[a][1]=son[b][1];
	updata(a);
}
int merge(int a,int b){
	if(!a||!b) return a+b;
	if(rnd[a]>rnd[b]){
		int p=++tot;newpoint(p,a);
		son[p][1]=merge(son[p][1],b);
		updata(p);return p;
	}	
	int p=++tot;newpoint(p,b);
	son[p][0]=merge(a,son[p][0]);
	updata(p);return p;
}
void split(int now,int k,int &x,int &y){
	if(!now){
		x=y=0;
		return ;
	}
	if(k<val[now]){
		y=++tot;newpoint(y,now);
		split(son[y][0],k,x,son[y][0]);
		updata(y);
	}
	else{
		x=++tot;newpoint(x,now);
		split(son[x][1],k,son[x][1],y);
		updata(x);
	}
}
void Insert(int &rt,int w){
	int xa=0,ya=0,z=0;split(rt,w,xa,ya);
	z=newnode(w);rt=merge(merge(xa,z),ya);
}
void Delete(int &rt,int w){
	int xa=0,ya=0,z=0,xb=0,yb=0;
	split(rt,w,xa,ya);split(xa,w-1,xb,yb);
	rt=merge(merge(xb,son[yb][0]),merge(son[yb][1],ya));
}
int rankth(int &rt,int w){
	int xa,ya;split(rt,w-1,xa,ya);
	int res=siz[xa]+1;rt=merge(xa,ya);
	return res;
}
int kth(int p,int w){
	if(w==siz[son[p][0]]+1) return val[p];
	if(w<=siz[son[p][0]]) return kth(son[p][0],w);
	return kth(son[p][1],w-siz[son[p][0]]-1);
}
int pre(int &rt,int w){
	int xa,ya;split(rt,w-1,xa,ya);
	if(!xa) return -INF;
	int k=siz[xa],res=kth(xa,k);
	rt=merge(xa,ya);return res;
}
int nxt(int &rt,int w){
	int xa,ya;split(rt,w,xa,ya);
	if(!ya) return INF;
	int res=kth(ya,1);rt=merge(xa,ya);
	return res; 
}
signed main()
{
	read(n);
	for(int i=1;i<=n;i++){
		int v,opt,x;read(v);read(opt);read(x);rot[i]=rot[v];
		if(opt==1) Insert(rot[i],x);
		if(opt==2) Delete(rot[i],x);
		if(opt==3) printf("%d\n",rankth(rot[i],x));
		if(opt==4) printf("%d\n",kth(rot[i],x));
		if(opt==5) printf("%d\n",pre(rot[i],x));
		if(opt==6) printf("%d\n",nxt(rot[i],x));
	}
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值