码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ3224_普通平衡树_KEY

时间:2018-03-08 00:08:16      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:log   pos   gpo   数据   break   body   www   get   int   

题目传送门

平衡二叉树(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);
        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

标签:log   pos   gpo   数据   break   body   www   get   int   

原文地址:https://www.cnblogs.com/Cptraser/p/8525178.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!