Size Balanced Tree

Size Balanced Tree,SBT,被广大算法竞赛选手“亲切”地成为傻逼树。当然作为由国内神犇陈启峰(%%%%%%)发明的一种优秀的二叉排序树,这种数据结构一点儿也不傻逼,甚至优于被公认为十分好写好用的Splay Tree。动动嘴皮子的事情谁都会,接下来就让我们来实现以下这个数据结构。
SBT主要的思想是,用子树的大小作为维护这棵平衡树的关键字。
首先SBT最基础的还是一类基本的左旋右旋操作。不过因为涉及到每一棵子树的大小,所以要在普通平衡树的基础上加上子树大小的转移。

#define N 1000001
int jis=0,r[N],l[N],s[N],d[N],host=0;//jis是总节点数,r是右孩子,l是左孩子,s代表字树的大小,d代表节点的值,host代表树的根节点
void zig(int &a){//右旋操作
    int b=l[a];
    l[a]=r[b];
    r[b]=a;
    s[b]=s[a];
    s[a]=s[l[a]]+s[r[a]]+1;
    a=b;
}
void zag(int &a){//左旋操作
    int b=r[a];
    r[a]=l[b];
    l[b]=a;
    s[b]=s[a];
    s[a]=s[l[a]]+s[r[a]]+1;
    a=b;
}

再来实现以下在树中插入新元素。

void insert(int &a,int data){
    if(!a){
        a=++jis;
        d[a]=data;
        s[a]=1;
        r[a]=l[a]=0;
    } else{
        s[a]++;
        if(data<d[a]) insert(l[a],data); else insert(r[a],data);
        mt(a,data>=d[a]);
    }
}

这个mt,即Maintain是个什么鬼呢?写完插入后,这棵树难免会有不平衡的情况出现,我们需要用Maintain函数来修复它。首先我们需要知道,SBT有这么两个性质。s[r[t]]≥s[l[l[t]]],s[r[l[t]]],和s[l[t]]≥s[l[r[t]]],s[r[r[t]]],如果不符合这两条性质,就要用左旋和右旋进行调整了!

void mt(int &t,bool pd){
    if(!pd){
        if(s[l[l[t]]]>s[r[t]]) zig(t);
        else if(s[r[l[t]]]>s[r[t]]) zag(l[t]),zig(t);
        else return;
    }else{
        if(s[r[r[t]]]>s[l[t]]) zag(t);
        else if(s[l[r[t]]]>s[l[t]]) zig(r[t]),zag(t);
        else return;
    }
    mt(l[t],0);
    mt(r[t],1);
    mt(t,0);
    mt(t,1);
}

请手模体验这个神奇的函数。十分的工整和好写,又十分的神奇。
当我们维护好了这棵树之后呢,就可以使用这棵树的性质进行一些高级的操作,比如查找元素,查找第k大的元素,查找一个元素的前驱和后继或者删除一个元素。

int Find(int t,int data){
    if(t==0||d[t]==data) return t;
    if(d[t]>data) return Find(l[t],data);
    else return Find(r[t],data);
}
int Delete(int &u,int v)//如果没有找到要删除的节点,就删除最后一个访问的节点并记录
{
    s[u]--;
    if((v==d[u])||(v<d[u]&&l[u]==0)||(v>d[u]&&r[u]==0))
    {
        int rr=d[u];
        if(l[u]==0||r[u]==0)
            u=l[u]+r[u];
        else
            d[u]=Delete(l[u],d[u]+1);
        return rr;
    }
    else
    {
        if(v<d[u])
            return Delete(l[u],v);
        else
            return Delete(r[u],v);
    }
}
int Rank(int t,int data){
    if(T==0) return 1;
    if(data<=d[t]) return Rand(l[t],data);
    else return s[l[t]]+1+rank(r[t],data);
}
int Succ(int t,int data){
    if(t==0) return t;
    if(data>=d[t]) return Succ(r[t],data);
    else{
        int cache=Succ(l[t],data);
        return cache==0? t:cache;
    }
}
int Pred(int t,int data){
    if(t==0) return t;
    if(data<=d[t]) return Pred(r[t],data);
    else {
        int cache=Pred(l[t],data);
        return cache==0? t:cache;
    }
}
int select(int a,int rank){
    if(rank==s[l[a]]+1) return d[a];
    if(rank<=s[l[a]]) return select(l[a],rank);
    else return select(r[a],rank-1-s[l[a]]);
}

打完感觉手在冒烟。
参考资料

猜你喜欢

转载自www.cnblogs.com/jiaangk/p/9203757.html