我们可以看到,如果一个二叉排序树节点插入的顺序是随机的,这样我们得到的二叉排序树大多数情况下是平衡的,即使存在一些极端情况,但是这种情况发生的概率很小,所以我们可以这样建立一颗二叉排序树,而不必要像AVL那样旋转,可以证明随机顺序建立的二叉排序树在期望高度是,但是某些时候我们并不能得知所有的带插入节点,打乱以后再插入。所以我们需要一种规则来实现这种想法,并且不必要所有节点。也就是说节点是顺序输入的,我们实现这一点可以用Treap。
Treap=Tree+Heap
void insert(int &k,int x) { if(k==0) { size++;k=size; tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand(); return; } tr[k].size++; if(tr[k].v==x)tr[k].w++;//每个结点顺便记录下与该节点相同值的数的个数 else if(x>tr[k].v) { insert(tr[k].r,x); if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);//维护堆性质 } else { insert(tr[k].l,x); if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k); } }
void del(int &k,int x) { if(k==0)return; if(tr[k].v==x) { if(tr[k].w>1) { tr[k].w--;tr[k].size--;return;//若不止相同值的个数有多个,删去一个 } if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;//有一个儿子为空 else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd) rturn(k),del(k,x); else lturn(k),del(k,x); } else if(x>tr[k].v) tr[k].size--,del(tr[k].r,x); else tr[k].size--,del(tr[k].l,x); }
proceduredel(x:longint); var now,MinMax,p:point; begin now:=root;//root为根指针 null^.x:=x; whilenow^.x<>xdo begin p:=now; ifnow^.x>xthen now:=now^.l else now:=now^.r; end; ifnow=nullthen//没找到X exit; ifnow^.l<>nullthen//左子树不为空,往左找 begin MinMax:=now^.l; p:=now; whileMinMax^.r<>nulldo begin p:=MinMax; MinMax:=MinMax^.r; end; now^.x:=MinMax^.x; ifp<>nowthen p^.r:=MinMax^.l else p^.l:=MinMax^.l; dispose(MinMax); end else ifnow^.r<>nullthen//右子树不为空,往右找 begin MinMax:=now^.r; p:=now; whileMinMax^.l<>nulldo begin p:=MinMax; MinMax:=MinMax^.l; end; now^.x:=MinMax^.x; ifp<>nowthen p^.l:=MinMax^.r else p^.r:=MinMax^.r; dispose(MinMax); end else//X本身是叶子 begin ifp^.x>xthen p^.l:=null else p^.r:=null; dispose(now); end; end;
void rturn(int &k) { int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k; k=t; } void lturn(int &k) { int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k; tk=t; }
//by hzwer #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; struct data{ int l,r,v,size,rnd,w; }tr[100005]; int n,size,root,ans; void update(int k)//更新结点信息 { tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w; } void rturn(int &k) { int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k; tr[t].size=tr[k].size;update(k);k=t; } void lturn(int &k) { int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k; tr[t].size=tr[k].size;update(k);k=t; } void insert(int &k,int x) { if(k==0) { size++;k=size; tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand(); return; } tr[k].size++; if(tr[k].v==x)tr[k].w++; else if(x>tr[k].v) { insert(tr[k].r,x); if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k); } else { insert(tr[k].l,x); if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k); } } void del(int &k,int x) { if(k==0)return; if(tr[k].v==x) { if(tr[k].w>1) { tr[k].w--;tr[k].size--;return; } if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r; else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd) rturn(k),del(k,x); else lturn(k),del(k,x); } else if(x>tr[k].v) tr[k].size--,del(tr[k].r,x); else tr[k].size--,del(tr[k].l,x); } int query_rank(int k,int x) { if(k==0)return 0; if(tr[k].v==x)return tr[tr[k].l].size+1; else if(x>tr[k].v) return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x); else return query_rank(tr[k].l,x); } int query_num(int k,int x) { if(k==0)return 0; if(x<=tr[tr[k].l].size) return query_num(tr[k].l,x); else if(x>tr[tr[k].l].size+tr[k].w) return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w); else return tr[k].v; } void query_pro(int k,int x) { if(k==0)return; if(tr[k].v<x) { ans=k;query_pro(tr[k].r,x); } else query_pro(tr[k].l,x); } void query_sub(int k,int x) { if(k==0)return; if(tr[k].v>x) { ans=k;query_sub(tr[k].l,x); } else query_sub(tr[k].r,x); } int main() { scanf("%d",&n); int opt,x; for(int i=1;i<=n;i++) { scanf("%d%d",&opt,&x); switch(opt) { case 1:insert(root,x);break; case 2:del(root,x);break; case 3:printf("%d\n",query_rank(root,x));break; case 4:printf("%d\n",query_num(root,x));break; case 5:ans=0;query_pro(root,x);printf("%d\n",tr[ans].v);break; case 6:ans=0;query_sub(root,x);printf("%d\n",tr[ans].v);break; } } return 0; }