题解可持久化平衡树

Posted Refined_heart

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解可持久化平衡树相关的知识,希望对你有一定的参考价值。

Problem

\\(\\text{Solution:}\\)

考虑用 fhq_treap 来实现这个东西。

每次的新建版本,我们可以新建一个根,并直接利用 merge 和 split 操作在上一个版本上利用信息。

注意 split 和 merge 中都需要新建节点,否则会影响之前版本的结构。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=5e5+10;
const int INF=1000000001;
const int N=MAXN<<6;
int rt[MAXN],tr[N][2];
int siz[N],cv[N],val[N];
int cnt;
inline int read() {
	int s=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)) {
		if(ch==\'-\')w=-1;
		ch=getchar();
	}
	while(isdigit(ch)) {
		s=s*10-48+ch;
		ch=getchar();
	}
	return w*s;
}
inline int rd(){return rand()<<15|rand();}
inline int bd(int v){
	val[++cnt]=v;
	siz[cnt]=1;
	cv[cnt]=rd();
	return cnt;
}
inline void pushup(int x){siz[x]=siz[tr[x][0]]+siz[tr[x][1]]+1;}
void split(int now,int k,int &x,int &y){
	if(!now){x=y=0;return;}
	if(val[now]<=k){
		x=++cnt;
		tr[x][0]=tr[now][0];
		tr[x][1]=tr[now][1];
		val[x]=val[now];
		siz[x]=siz[now];
		cv[x]=cv[now];
		split(tr[x][1],k,tr[x][1],y);
		pushup(x);
	}
	else{
		y=++cnt;
		tr[y][0]=tr[now][0];
		tr[y][1]=tr[now][1];
		val[y]=val[now];
		siz[y]=siz[now];
		cv[y]=cv[now];
		split(tr[y][0],k,x,tr[y][0]);
		pushup(y);
	}
}
int merge(int x,int y){
	if(!x||!y)return x+y;
	if(cv[x]<cv[y]){
		int p=++cnt;
		tr[p][0]=tr[x][0];
		tr[p][1]=tr[x][1];
		val[p]=val[x];
		siz[p]=siz[x];
		cv[p]=cv[x];
		tr[p][1]=merge(tr[p][1],y);
		pushup(p);return p;
	}
	else{
		int p=++cnt;
		tr[p][0]=tr[y][0];
		tr[p][1]=tr[y][1];
		siz[p]=siz[y];
		val[p]=val[y];
		cv[p]=cv[y];
		tr[p][0]=merge(x,tr[p][0]);
		pushup(p);return p;
	}
}
void del(int &root,int v){
	int xA=0,yA=0,zA=0;
	split(root,v,xA,zA);
	split(xA,v-1,xA,yA);
	yA=merge(tr[yA][0],tr[yA][1]);
	root=merge(merge(xA,yA),zA);
}
void Ins(int &root,int v){
	int x=0,y=0;
	split(root,v,x,y);
	root=merge(merge(x,bd(v)),y);
}
int n,opt;
int kth(int now,int k){
	if(k<=siz[tr[now][0]])return kth(tr[now][0],k);
	if(k==siz[tr[now][0]]+1)return now;
	return kth(tr[now][1],k-siz[tr[now][0]]-1);
}
void dfs(int x){
	if(tr[x][0])dfs(tr[x][0]);
	printf("%lld ",val[x]);
	if(tr[x][1])dfs(tr[x][1]);
}
signed main(){
	n=read();
//	dfs(rt[0]);puts("");
	for(int i=1;i<=n;++i){
		int v=read(),x;
		opt=read();x=read();
		rt[i]=rt[v];
		if(opt==1){Ins(rt[i],x);}
		else if(opt==2){del(rt[i],x);}
		else if(opt==3){
			int A=0,B=0;
			split(rt[i],x-1,A,B);
			printf("%lld\\n",siz[A]+1);
			rt[i]=merge(A,B);
		}
		else if(opt==4){printf("%lld\\n",val[kth(rt[i],x)]);}
		else if(opt==5){
			int A=0,B=0;
			split(rt[i],x-1,A,B);
			if(!A){
				puts("-2147483647");
				continue;
			}
			printf("%lld\\n",val[kth(A,siz[A])]);
			rt[i]=merge(A,B);
		}
		else{
			int A=0,B=0;
			split(rt[i],x,A,B);
			if(!B){
				puts("2147483647");
				continue;
			}
			printf("%lld\\n",val[kth(B,1)]);
			rt[i]=merge(A,B);
		}
//		dfs(rt[i]);puts("");
	}
	return 0;
}

注意没有前驱后继的处理,不能在一开始就加进去,那样的排名是不对的。

细节上就是注意新开节点。

以上是关于题解可持久化平衡树的主要内容,如果未能解决你的问题,请参考以下文章

可持久化平衡树

洛谷 P3835 模板可持久化平衡树

可持久化平衡树

[luogu3835]可持久化平衡树

可持久化平衡树

P3919 模板可持久化数组(可持久化线段树/平衡树)