【模板】可持久化平衡树

link

借这一篇随笔说一下我对可持久化数据结构的一些思考。

先说题目本身。平衡树可持久化一般用无旋Treap来实现,因为它没有旋转,也就是说假如你指向了某个子树,那么子树内的东西就不会改变,而这一点Splay或者Treap就不太好搞(替罪羊暂时不会写【汗颜】)。于是按照主席树一样的思路,在操作的过程中每次都新建一个节点使之和旧节点完全一样,接下来考虑两个节点可能相异的地方有哪些。对于split操作来说,一个点属于左半树为例,新节点和旧节点显然左子树所有信息相同,不同的只有右子树的链接,递归处理即可。merge则更加简单,新建一个节点全等于优先级小的点之后考虑有什么变化,显然可以想到新旧节点只会有一个孩子有变化,那么递归处理即可。空间开销比较大,所幸本题空间给的也大(1000MB),便没有什么问题了。

至于可持久化数据结构,几道模板的描述都是什么基于某个历史版本的操作。其实我觉得全部描述成一棵树比较合适,因为相当于每个历史状态单前驱多后继,可以解决的问题就多了起来。

code

#include<cstdio>
#include<cstdlib>
#include<ctime>
#define zczc
using namespace std;
const int N=500010;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

#define lc t[x].l
#define rc t[x].r
struct node{
	int l,r,data,size,p;
}t[N<<6];
int ti,root[N],cnt;
inline void print(int x){
	if(!x)return;
	printf("%d %d %d&%d\n",x,t[x].data,lc,rc);
	print(lc);print(rc);
}
inline void pushup(int x){
	t[x].size=t[lc].size+t[rc].size+1;
}
inline int newone(int val){
	t[++cnt]=(node){0,0,val,1,rand()};return cnt;
}
inline void split(int x,int val,int &a,int &b){
	if(!x){a=b=0;return;}
	int y=x;x=++cnt;t[x]=t[y];
	if(t[x].data<=val){a=x;split(rc,val,rc,b);}
	else{b=x;split(lc,val,a,lc);}pushup(x);
}
inline int merge(int x,int y){
	if(!x||!y)return x+y;int s=++cnt;
	if(t[x].p<t[y].p){t[s]=t[x];t[s].r=merge(t[s].r,y);}
	else{t[s]=t[y];t[s].l=merge(x,t[s].l);}pushup(s);return s;
}
inline void insert(int pl,int val){
	int a,b;split(root[pl],val,a,b);
	root[ti]=merge(merge(a,newone(val)),b);
}
inline void delet(int pl,int val){
	int a,b,c;split(root[pl],val,a,c);
	split(a,val-1,a,b);b=merge(t[b].l,t[b].r);
	root[ti]=merge(merge(a,b),c);
}
inline int get(int x,int val){
	if(t[lc].size+1==val)return t[x].data;
	if(t[lc].size>=val)return get(lc,val);
	else return get(rc,val-t[lc].size-1);
}
inline int getmax(int pl,int val){
	int a,b;split(root[pl],val-1,a,b);
	return get(a,t[a].size);
}
inline int getmin(int pl,int val){
	int a,b;split(root[pl],val,a,b);
	return get(b,1);
}
inline int getrank(int pl,int val){
	int a,b;split(root[pl],val-1,a,b);
	return t[a].size+1;
}
#undef lc
#undef rc

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	srand(time(0));
	int m,op,h,val;
	read(m);
	for(ti=1;ti<=m;ti++){
		read(h);read(op);read(val);
		switch(op){
			case 1:insert(h,val);break;
			case 2:delet(h,val);break;
			case 3:printf("%d\n",getrank(h,val));break;
			case 4:printf("%d\n",get(root[h],val));break;
			case 5:printf("%d\n",getmax(h,val));break;
			case 6:printf("%d\n",getmin(h,val));break;
		}
		if(op>2)root[ti]=root[h];
		//print(root[ti]);printf("\n");
	}
	
	return 0;
}
posted @ 2022-04-09 11:13  Feyn618  阅读(97)  评论(0编辑  收藏  举报