【TYVJ1728】【洛谷P3369】—普通平衡树(FHQ_Treap)

传送门

原谅我一直以为这叫 T r e a p 防火墙Treap

不过这确实比旋转 T r e a p Treap 好写多了,还支持可持久化

主要就是 m e r g e merge S p l i t Split

看看代码就懂了

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=100006;
int siz[N],val[N],n,key[N],son[N][2];
#define lc(u) (son[u][0])
#define rc(u) (son[u][1])
int tot,rt=0,seed=233,mod=19260817;
inline int rnd(){
	return seed=int(seed*482711ll%2147483647);
}
inline int addnode(int x){
	siz[++tot]=1,val[tot]=x,key[tot]=rnd();
	lc(tot)=rc(tot)=0;return tot;
}
inline int pushup(int u){
	siz[u]=siz[lc(u)]+siz[rc(u)]+1;
}
inline void split(int u,int &a,int &b,int k){
	if(u==0){
		a=b=0;return;
	}
	if(val[u]<=k){
		a=u,split(rc(u),rc(a),b,k);
	}
	else {
		b=u,split(lc(u),a,lc(b),k);
	}
	pushup(u);
}
inline void merge(int &u,int a,int b){
	if(!a||!b){
		u=a+b;return;
	}
	if(key[a]<key[b])u=a,merge(rc(u),rc(a),b);
	else u=b,merge(lc(u),a,lc(b));
	pushup(u);
}
inline int find(int x,int k){
	while(siz[lc(x)]+1!=k){
		if(siz[lc(x)]>=k)
			x=lc(x);
		else k-=siz[lc(x)]+1,x=rc(x);
	}
	return x;
}
inline void insert(int k){
	int r1=0,r2=0,u;
	u=addnode(k);
	split(rt,r1,r2,k);
	merge(r1,r1,u);
	merge(rt,r1,r2);
}
inline void delet(int x){
	int r1=0,r2=0,r3=0;
	split(rt,r1,r2,x);
	split(r1,r1,r3,x-1);
	merge(r3,lc(r3),rc(r3));
	merge(r1,r1,r3);
	merge(rt,r1,r2);
}
inline int getrk(int k){
	int r1=0,r2=0;
	split(rt,r1,r2,k-1);
	int res=siz[r1]+1;
	merge(rt,r1,r2);
	return res;
}
inline int getval(int k){
	return val[find(rt,k)];
}
inline int pre(int k){
	int r1=0,r2=0;
	split(rt,r1,r2,k-1);
	int u=find(r1,siz[r1]);merge(rt,r1,r2);
	return val[u];
}
inline int nxt(int k){
	int r1=0,r2=0;
	split(rt,r1,r2,k);
	int u=find(r2,1);merge(rt,r1,r2);
	return val[u];
}
int main(){
	srand(time(NULL));
	n=read();
	for(int i=1;i<=n;i++){
		int op=read(),x=read();
		switch(op){
			case 1:{
				insert(x);
				break;
			}
			case 2:{
				delet(x);
				break;
			}
			case 3:{
				cout<<getrk(x)<<'\n';
				break;
			}
			case 4:{
				cout<<getval(x)<<'\n';
				break;
			}
			case 5:{
				cout<<pre(x)<<'\n';
				break;
			}
			case 6:{
				cout<<nxt(x)<<'\n';
				break;
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/86610945