BZOJ3224_普通平衡树_KEY

题目传送门

平衡二叉树(Balanced Binary Tree)具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。

平衡树是一种在信息竞赛中常用的数据结构,而Treap也是其中之一。说实话花了一天来屮这个Treap。

Treap简单地来说就是二叉搜索树的升级版,只不过在其基础上增加了一个rand值,并利用堆维护rand值,使二叉搜索树的rand值满足堆的性质。

从而保证Treap的高度基本为logN。

Treap的核心就是一个Rotate,它能保证Treap的性质。

插入:像二叉搜索树一样插入,在子节点不满足堆的性质时Rotate。

删除:先找到节点,如果没有儿子,直接删除。有一个儿子,直接将儿子覆盖到当前节点。有两个儿子,Rotate之后递归向下。

其他操作较简单,看code有解释。

code:

#include <cstdio>
#include
<cstdlib> #include <cstring> int read() { char c;while(c=getchar(),(c<'0'||c>'9')&&c!='-'); int x=0,y=1;c=='-'?y=-1:x=c-'0'; while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0'; return x*y; } int N,dist; struct Treap{ int tr[100005][2],cnt,ks[100005],v[100005],tot[100005]; int f[100005],root; Treap(){ memset(tr,0,sizeof tr); memset(ks,0,sizeof ks); memset(v,0,sizeof v); cnt=0; } void rotate(int &x,int o)//旋转 { int k=tr[x][o]; tr[x][o]=tr[k][o^1]; tr[k][o^1]=x; f[k]=f[x];//更新 f[x]=f[tr[x][0]]+f[tr[x][1]]+tot[x]; x=k; } void Insert(int &x,int val)//插入节点 { if(!x){ x=++cnt; ks[x]=rand(); v[x]=val; tot[x]=1;//当前节点共有几个相同的值 f[x]=1; return ; }f[x]++;//统计当前这个节点的子树共有几个节点 if(val==v[x]){tot[x]++;return ;} int to=val>v[x]; Insert(tr[x][to],val); if(ks[tr[x][to]]>ks[x])rotate(x,to);//不满足堆的性质,Rotate return ; } void Delete(int &x,int val)//删除 { if(!x)return ; if(val==v[x]){ if(tot[x]>1){tot[x]--;f[x]--;return ;} if(!tr[x][0]&&!tr[x][1]){v[x]=tot[x]=ks[x]=0;x=0;return ;} if(!(tr[x][0]*tr[x][1])){ x=tr[x][0]+tr[x][1]; return ; } rotate(x,0); Delete(x,val);//递归向下 return ; } int to=val>v[x]; f[x]--;//减去总结点数 Delete(tr[x][to],val);
     f[x]=f[tr[x][0]]+f[tr[x][1]]+tot[x];
return ; } int QueryX(int x,int val) { if(!x)return 0; if(v[x]==val)return f[tr[x][0]]+1;//小细节,可以直接return左子树总结点+1 int to=val>v[x]; return QueryX(tr[x][to],val)+(to?(f[tr[x][0]]+tot[x]):0);//如果是访问右子树retun之后要加上f[tr[x][0]]+tot[x]
     //查询X的排名 }
int QueryK(int x,int kth) { if(!x)return 0; if(kth<=f[tr[x][0]])return QueryK(tr[x][0],kth);//在左子树 if(kth>f[tr[x][0]]+tot[x])return QueryK(tr[x][1],kth-(f[tr[x][0]]+tot[x]));//在右子树 return v[x];//查询排名为X的数 } int pre(int x,int val)//前驱 { if(!x)return 0; if(v[x]>=val)pre(tr[x][0],val); else{ dist=x; pre(tr[x][1],val); } } int bac(int x,int val)//后继 { if(!x)return 0; if(v[x]<=val)bac(tr[x][1],val); else{ dist=x; bac(tr[x][0],val); } } }T; int main() { int W=('Y'+'u'+'a'+'o')*('S'+'h'+'i')*('D'+'o'+'g'); srand(W); N=read(); while(N--){ int o=read(),x=read(); switch(o){ case 1:T.Insert(T.root,x);break; case 2:T.Delete(T.root,x);break; case 3:printf("%d\n",T.QueryX(T.root,x));break; case 4:printf("%d\n",T.QueryK(T.root,x));break; case 5:dist=0,T.pre(T.root,x),printf("%d\n",T.v[dist]);break; case 6:dist=0,T.bac(T.root,x),printf("%d\n",T.v[dist]);break; } } }

 

posted @ 2018-03-07 20:34  Cptraser  阅读(191)  评论(0编辑  收藏  举报