1. 程式人生 > 其它 >P3835-[模板]可持久化平衡樹【無旋Treap】

P3835-[模板]可持久化平衡樹【無旋Treap】

正題

題目連結:https://www.luogu.com.cn/problem/P3835


題目大意

一個空可重集,要求支援

  • 插入一個數\(x\)
  • 刪除一個數\(x\)
  • 詢問一個數\(x\)的排名
  • 詢問排名第\(x\)的數字
  • 詢問\(x\)的前驅
  • 詢問\(x\)的後繼

但是所有操作都是基於某個歷史版本

\(1\leq n\leq 5\times 10^5,1\leq |x|\leq 10^9\)


解題思路

挺好寫的,就是一個\(FHQ\),可持久化部分分裂和主席樹差不多,合併和線段樹合併差不多。
空間記得開大點。

時空間複雜度都是\(O(n\log n)\)的。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e7+10;
int n,rt[510000];
struct FHQ{
	int cnt,w[N],siz[N],rnk[N],t[N][2];
	int NewNode(int val)
	{w[++cnt]=val;siz[cnt]=1;rnk[cnt]=rand();return cnt;}
	void PushUp(int x){
		siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;
		return;
	}
	void Cpy(int x,int y){
		siz[x]=siz[y];rnk[x]=rnk[y];w[x]=w[y];
		t[x][0]=t[y][0];t[x][1]=t[y][1];return;
	}
	void Split(int &x,int &y,int p,int k){
		if(!p){x=y=0;return;}
		int now=++cnt;Cpy(now,p);
		if(w[p]<=k)x=now,Split(t[now][1],y,t[p][1],k);
		else y=now,Split(x,t[now][0],t[p][0],k);
		PushUp(now);return;
	}
	int Merge(int x,int y){
		if(!x||!y)return x|y;
		int now=++cnt;
		if(rnk[x]<=rnk[y]){
			Cpy(now,x);
			t[now][1]=Merge(t[x][1],y);
		}
		else{
			Cpy(now,y);
			t[now][0]=Merge(x,t[y][0]);
		}
		PushUp(now);return now;
	}
	int Find(int x,int k){
		if(siz[t[x][0]]>=k)return Find(t[x][0],k);
		if(siz[t[x][0]]+1==k)return x;
		return Find(t[x][1],k-siz[t[x][0]]-1);
	}
	void Insert(int &rt,int val){
		int x,y;
		Split(x,y,rt,val);
		rt=Merge(Merge(x,NewNode(val)),y);
		return;
	}
	void Delete(int &rt,int val){
		int x,y,z;
		Split(x,z,rt,val);
		Split(x,y,x,val-1);
		y=Merge(t[y][0],t[y][1]);
		rt=Merge(Merge(x,y),z);
		return;
	}
	int GetRank(int rt,int val){
		int x,y;
		Split(x,y,rt,val-1);
		return siz[x]+1;
	}
	int GetVal(int rt,int rk)
	{return w[Find(rt,rk)];}
	int GetPre(int rt,int val){
		int x,y;
		Split(x,y,rt,val-1);
		return w[Find(x,siz[x])];
	}
	int GetNxt(int rt,int val){
		int x,y;
		Split(x,y,rt,val);
		return w[Find(y,1)];
	}
}T;
int main()
{
	scanf("%d",&n);
	T.NewNode(-2147483647);
	T.NewNode(2147483647);
	rt[0]=T.Merge(1,2);
	for(int i=1,v,op,x;i<=n;i++){
		scanf("%d%d%d",&v,&op,&x);rt[i]=rt[v];
		if(op==1)T.Insert(rt[i],x);
		else if(op==2)T.Delete(rt[i],x);
		else if(op==3)printf("%d\n",T.GetRank(rt[i],x)-1);
		else if(op==4)
			printf("%d\n",T.GetVal(rt[i],x+1));
		else if(op==5)printf("%d\n",T.GetPre(rt[i],x));
		else if(op==6)printf("%d\n",T.GetNxt(rt[i],x));
	}
	return 0;
}