BZOJ3224_普通平衡树_KEY
Posted Cptraser
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; } } }
以上是关于BZOJ3224_普通平衡树_KEY的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3224: Tyvj 1728 普通平衡树(spaly)