【洛谷P2596】【ZJOI2006】—书架(FHQ_Treap)

传送门

考虑到每个点需要维护一个numnum和一个valval分别表示在书架内的排名和编号
我们再记录一个to[x]to[x]表示编号xx的书的排名

考虑以valval为优先级建TreapTreap

对应5种操作:

1:把ss先删去再将排名设成一个最小的数插入
2:把ss删去后把排名设成一个最大数插入
3:把sss+Ts+T提出来交换一下他们的numnumvalval,再交换一下toto就可以了
4:求ss的排名
5:求第kk大,维护一下sizesize就可以了

都是平衡树常规操作

调了40多分钟发现randrand写丑了,也是没谁了

#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=500006;
int siz[N],son[N][2],num[N],val[N],tot,key[N],to[N],seed,rt,n,m,mn,mx;
#define lc(u) son[u][0]
#define rc(u) son[u][1]
inline int rnd(){
	return ((rand()*1ll)<<15)%1000000000;
}
inline int addnode(int x,int p){
	siz[++tot]=1,val[tot]=x,num[tot]=p,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 p){
	int r1=0,r2=0,u;
	u=addnode(k,p);
	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 num[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 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 u;
}
char op[10];
int main(){
	srand(time(NULL));
	n=read(),m=read();
	mx=n,mn=1;
	for(int i=1;i<=n;i++){
		int k=read();insert(i,k),to[k]=i;
	}
	for(int i=1;i<=m;i++){
		scanf("%s",op);int u=read();
		switch(op[0]){
			case 'T':{
				delet(to[u]),to[u]=--mn;
				insert(to[u],u);	
				break;
			}
			case 'B':{
				delet(to[u]),to[u]=++mx;
				insert(to[u],u);
				break;
			}
			case 'I':{
				int k=read(),p,now;
				if(k==0)break;
				if(k==-1)p=pre(to[u]),now=nxt(to[num[p]]);
				else if(k==1)p=nxt(to[u]),now=pre(to[num[p]]);
				swap(to[num[p]],to[u]),swap(num[p],num[now]);
				break;
			}
			case 'A':{
				cout<<getrk(to[u])-1<<'
';
				break;
			}
			case 'Q':{
				cout<<getval(u)<<'
';
				break;
			}
		}
	}
}