FHQ treap
每个点维护两个权值:\(\text{val},\text{pri}\),其中 \(\text {val}\) 满足二叉搜索树性质,\(\text{pri}\) 满足大根堆。
\(\text{pri}\) 是随机生成的。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<random>
using namespace std;
mt19937 rnd(time(0));
const int N=1e6+10;
int cnt,rt;
int ls[N],rs[N],val[N],pri[N],siz[N];
void update(int u) {
siz[u]=siz[ls[u]]+siz[rs[u]]+1;
}
void addn(int x) {
siz[++cnt]=1,val[cnt]=x,pri[cnt]=rnd()%N,ls[cnt]=rs[cnt]=0;
}
void split(int u,int x,int &L,int &R) {
if(u==0) {L=R=0; return ;}
if(val[u]<=x) {
L=u;
split(rs[u],x,rs[u],R);
} else {
R=u;
split(ls[u],x,L,ls[u]);
}
update(u);
}
int merge(int L,int R) {
if(L==R) return L;
if(L==0||R==0) return L^R;
if(pri[L]>pri[R]) {
rs[L]=merge(rs[L],R);
update(L); return L;
} else {
ls[R]=merge(L,ls[R]);
update(R); return R;
}
}
void ins(int x) {
int L,R;
split(rt,x,L,R);
addn(x);
int tmp=merge(L,cnt);
rt=merge(tmp,R);
}
void del(int x) {
int L,R,p;
split(rt,x,L,R);
split(L,x-1,L,p);
p=merge(ls[p],rs[p]);
rt=merge(merge(L,p),R);
}
int rnk(int x) {
int L,R,Ans;
split(rt,x-1,L,R);
Ans=siz[L]+1;
rt=merge(L,R);
return Ans;
}
int kth(int u,int k) {
if(k==siz[ls[u]]+1) return u;
else if(k<=siz[ls[u]]) return kth(ls[u],k);
else return kth(rs[u],k-siz[ls[u]]-1);
}
int pre(int x) {
int L,R;
split(rt,x-1,L,R);
int Ans=val[kth(L,siz[L])];
rt=merge(L,R);
return Ans;
}
int suf(int x) {
int L,R;
split(rt,x,L,R);
int Ans=val[kth(R,1)];
rt=merge(L,R);
return Ans;
}
int main() {
int n; scanf("%d",&n);
for(; n; n--) {
int op,x; scanf("%d%d",&op,&x);
switch(op) {
case 1: ins(x); break;
case 2: del(x); break;
case 3: printf("%d\n",rnk(x)); break;
case 4: printf("%d\n",val[kth(rt,x)]); break;
case 5: printf("%d\n",pre(x)); break;
case 6: printf("%d\n",suf(x)); break;
}
}
return 0;
}