• 子树大小平衡树


    #include<cstdio>
    #define MXN 100000+3
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define nil 0
    #define LEFT false
    #define RIGHT true
    int val[MXN],size[MXN],fa[MXN],left[MXN],right[MXN],recycle[1001],root;
    int ntop,rtop=-1;
    int newnode(){
        int nw;
        if(rtop!=-1) nw=recycle[rtop--];
        else nw=++ntop;
        val[nw]=0;
        size[nw]=1;
        fa[nw]=nil;
        left[nw]=nil;
        right[nw]=nil;
        return nw;
    }
    int newnode(int k){
        int nw=newnode();
        val[nw]=k;
        return nw;
    }
    void rotate(int now){
        if(fa[now]==nil) return;
        int f=fa[now],gf=fa[f],l=left[now],r=right[now];
        fa[now]=gf;
        if(gf!=nil){
            if(left[gf]==f) left[gf]=now;
            if(right[gf]==f) right[gf]=now;
        }
        if(left[f]==now){
            right[now]=f;
            left[f]=r;
            if(r!=nil) fa[r]=f;
        }
        if(right[f]==now){
            left[now]=f;
            right[f]=l;
            if(l!=nil) fa[l]=f;
        }
        fa[f]=now;
        size[f]=size[left[f]]+size[right[f]]+1;
        size[now]=size[left[now]]+size[right[now]]+1;
        if(fa[now]==nil) root=now;
        return;
    }
    int mtl,mtr,mtb,mtrt; 
    void maintain(int now,bool type){
        fa[nil]=nil;
        left[nil]=nil;
        right[nil]=nil;
        mtl=left[now],mtr=right[now],mtb=nil;
        if(type==LEFT){
            if(size[left[mtl]]>size[mtr]){
                rotate(mtl);
                mtrt=mtl;
            }
            else if(size[right[mtl]]>size[mtr]){
                mtb=right[mtl];
                rotate(mtb);
                rotate(mtb);
                mtrt=mtb;
            }
            else return;
        }
        if(type==RIGHT){
            if(size[right[mtr]]>size[mtl]){
                rotate(mtr);
                mtrt=mtr;
            }
            else if(size[left[mtr]]>size[mtl]){
                mtb=left[mtr];
                rotate(mtb);
                rotate(mtb);
                mtrt=mtb;
            }
            else return;
        }
        maintain(left[mtrt],LEFT);
        maintain(right[mtrt],RIGHT);
        maintain(mtrt,LEFT);
        maintain(mtrt,RIGHT);
        return;
    }
    int search(int now,int k){
        if(now==nil) return nil;
        if(val[now]==k) return now;
        if(val[now]>k) return search(left[now],k);
        if(val[now]<k) return search(right[now],k);
    }
    int insert(int &now,int ins){
        if(root==nil) root=ins;
        else if(now==nil) now=ins;
        else{
            ++size[now];
            if(val[ins]<=val[now]){
                if(left[now]==nil){
                    left[now]=ins;
                    fa[ins]=now;
                }
                else insert(left[now],ins);
            }
            else{
                if(right[now]==nil){
                    right[now]=ins;
                    fa[ins]=now;
                }
                else insert(right[now],ins);
            }
            maintain(now,val[ins]>val[now]);
        }
        return ins;
    }
    void remove(int now,int k){
        if(now==nil) return;
        if(val[now]==k){
            if(left[now]==nil&&right[now]==nil){
                if(left[fa[now]]==now) left[fa[now]]=nil;
                else right[fa[now]]=nil;
                fa[now]=nil;
                if(now==root) root=nil;
                recycle[++rtop]=now;
                return;
            }
            else if(left[now]==nil){
                if(left[fa[now]]==now) left[fa[now]]=right[now];
                else right[fa[now]]=right[now];
                fa[right[now]]=fa[now];
                fa[now]=nil;
                if(now==root) root=right[now];
                recycle[++rtop]=now;
                return;
            }
            else if(right[now]==nil){
                if(left[fa[now]]==now) left[fa[now]]=left[now];
                else right[fa[now]]=left[now];
                fa[left[now]]=fa[now];
                fa[now]=nil;
                if(now==root) root=left[now];
                recycle[++rtop]=now;
                return;
            }
            else{
                int t=left[now];
                while(right[t]!=nil) t=right[t];
                val[now]=val[t];
                size[now]--;
                remove(left[now],val[t]);
                return;
            }
        }
        else{
            size[now]--;
            if(val[now]>k) remove(left[now],k);
            else remove(right[now],k);
        }
        return;
    }
    int select(int now,int k){
        if(now==nil) return nil;
        if(size[left[now]]+1==k) return now;
        if(size[left[now]]+1>=k) return select(left[now],k);
        if(size[left[now]]+1<k) return select(right[now],k-size[left[now]]-1);
    }
    int rank(int now,int k){
        if(now==nil) return 1;
        if(val[now]>=k) return rank(left[now],k);
        if(val[now]<k) return rank(right[now],k)+size[left[now]]+1; 
    }
    int get_prev(int now,int k){
        if(now==nil) return -200000000;
        if(val[now]<k) return max(val[now],get_prev(right[now],k));
        else return get_prev(left[now],k);
    }
    int get_succ(int now,int k){
        if(now==nil) return 200000000;
        if(val[now]>k) return min(val[now],get_succ(left[now],k));
        else return get_succ(right[now],k);
    }
    int main(){
        int n;
        scanf("%d",&n); 
        root=nil;
        int p,x;
        while(n--){
            scanf("%d%d",&p,&x);
            if(p==1) insert(root,newnode(x));
            if(p==2) remove(root,x);
            if(p==3) printf("%d
    ",rank(root,x));
            if(p==4) printf("%d
    ",val[select(root,x)]);
            if(p==5) printf("%d
    ",get_prev(root,x));
            if(p==6) printf("%d
    ",get_succ(root,x));
        }
        return 0;
    }
    Size Balanced Tree

    子树大小平衡树是一种平衡树,利用子树大小维护平衡。满足下面性质的二叉搜索树称为SBT:

    除根外,每棵树的大小不小于其兄弟的儿子的大小。

    性质十分简单。由于具有对称性(即若LR互为兄弟,则L大小不小于R的儿子大小,同时R大小不小于L的儿子大小),因此可以使树保持平衡。

    SBT基本操作为旋转。旋转与splay定义不同(貌似与很多平衡树相同),左旋一棵树指使其右子树的根成为这棵树新的根,右旋与左旋对称。

    主要的维护利用maintain,分以下四种情况:

    1、若某点右子树大小小于其左儿子的左子树大小,则右旋其本身,对称的情况是某点左子树大小小于其右儿子的右子树大小,则左旋其本身;

    2、若某点右子树大小小于其左儿子的右子树大小,则先左旋其左子树,再右旋其本身,另一种情况与这种情况对称。

    旋转之后,有一些树的大小发生变化,那么需要继续maintain,直到满足SBT性质。若上述maintain了子树A,则先maintainA的左右子树,再maintainA本身。

    有一种对maintain的改良方法,即maintain时只关注某一个子树是否小于其兄弟的儿子。不过我并不感觉改良了多少,大概改良了maintain次数,不过只是把四种情况分开讨论,原本四种情况也不会重叠。

    跑得还是比较快的。

     PS:

    子树大小平衡树虽然代码简单,但是有特殊情况不得不考虑:由于判断平衡时找到了自己的孙子,但这对于那些连儿子都没有的叶子结点来说是无能为力的,如果maintain叶子结点,用指针写会由于取NULL的值导致RE,用上述代码,即规定一个有值的NULL来写,则会因为NULL有儿子导致判断错误从而进行不必要的旋转甚至最终爆栈。因此maintain时可以不对叶子结点进行处理,也可以maintain时判断一下NULL的情况。上述代码每次maintain都将NULL的儿子指向自己,防止错误判断。

  • 相关阅读:
    正则表达式
    浅谈xss攻击
    四舍五入[银行家算法]
    POJ-2442-Sequence(二叉堆)
    Spring MVC 启动报错
    WebMagic 抓取图片并保存至本地
    spring 定时任务
    jquery validate 自定义校验方法
    位图
    二叉树(线索化)
  • 原文地址:https://www.cnblogs.com/halifuda/p/8087874.html
Copyright © 2020-2023  润新知