//平衡树 Treap //维护一个堆使得随机权值小(大)的数始终在上方 //使用随机权值目的:防止出题人卡 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; struct uio{ int l,r,siz,num,rd,tim;//左儿子,右儿子,子树大小+自己大小,点值,随机权值,出现次数 }treap[100001];//此代码为小根堆 即随机权值小的在上方 int n,size,ans,root;//size树的大小 void update(int k)//更新 { treap[k].siz=treap[treap[k].l].siz+treap[treap[k].r].siz+treap[k].tim; } void right(int &k)//右旋 { int x=treap[k].l; treap[k].l=treap[x].r; treap[x].r=k; treap[x].siz=treap[k].siz; update(k); k=x; } void left(int &k)//左旋 { int x=treap[k].r; treap[k].r=treap[x].l; treap[x].l=k; treap[x].siz=treap[k].siz; update(k); k=x; } void insert(int &k,int x) { if(k==0)//到达叶节点就开始插入 { size++; k=size; treap[k].siz=1; treap[k].tim=1; treap[k].num=x; treap[k].rd=rand(); return; } treap[k].siz++;//插入节点的每个父节点子树大小都加一 if(treap[k].num==x)//若已有此节点 treap[k].tim++;//出现次数加一 else { if(x>treap[k].num)//在右子树中 { insert(treap[k].r,x); if(treap[treap[k].r].rd<treap[k].rd)//子节点随机数比父节点小 left(k);//左旋 } else//在右子树中 { insert(treap[k].l,x); if(treap[treap[k].l].rd<treap[k].rd)//子节点随机数比父节点小 right(k);//右旋 } } } void del(int &k,int x) { if(k==0)//树中已无节点 return; if(treap[k].num==x)//找到了 { if(treap[k].tim>1)//出现次数大于一,直接删除即可 { treap[k].tim--; treap[k].siz--; return; } if(treap[k].l*treap[k].r==0)//左右子树有一棵为空 k=treap[k].l+treap[k].r;//直接把非空子树接在原树上 else { if(treap[treap[k].l].rd<treap[treap[k].r].rd)//每次下沉时与随机权值小的交换 以确保小根堆性质不变 right(k),del(k,x); else left(k),del(k,x); } } else//没找到 { if(x>treap[k].num)//在右子树中 { treap[k].siz--; del(treap[k].r,x); } else//在左子树中 { treap[k].siz--; del(treap[k].l,x); } } } int get_no(int k,int x) { if(k==0)//树中没有节点 return 0; if(treap[k].num==x)//找到x return treap[treap[k].l].siz+1;//结果为自己加左子树的大小 else if(x>treap[k].num)//在右子树 return treap[treap[k].l].siz+treap[k].tim+get_no(treap[k].r,x);//结果为递归回的结果加自己的大小加左子树的大小 else return get_no(treap[k].l,x);//在左子树 结果为递归回的结果 } int get_num(int k,int x) { if(k==0)//树中没有节点 return 0; if(x<=treap[treap[k].l].siz)//在左子树中 return get_num(treap[k].l,x); else if(x>(treap[treap[k].l].siz+treap[k].tim))//在右子树中 return get_num(treap[k].r,x-treap[treap[k].l].siz-treap[k].tim); else return treap[k].num;//在这个点上 } void pre(int k,int x) { if(k==0) return; if(treap[k].num<x)//在右子树中 { ans=k; pre(treap[k].r,x); } else pre(treap[k].l,x);//在左子树中 } void nxt(int k,int x) { if(k==0) return; if(treap[k].num>x)//在左子树中 { ans=k; nxt(treap[k].l,x); } else nxt(treap[k].r,x); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int u,v; scanf("%d%d",&u,&v); if(u==1) insert(root,v); if(u==2) del(root,v); if(u==3) printf("%d ",get_no(root,v)); if(u==4) printf("%d ",get_num(root,v)); if(u==5) { pre(root,v); printf("%d ",treap[ans].num); } if(u==6) { nxt(root,v); printf("%d ",treap[ans].num); } } return 0; }