0
点赞
收藏
分享

微信扫一扫

无旋平衡树

岛上码农 2022-04-15 阅读 66
算法

无旋平衡树(treap)

引子

在平衡树算法中,大多需要进行旋转操作,但旋转操作细节较多,容易写错,并且不好调试。所以我们需要不用旋转的平衡树——分裂合并 treap

那么这种平衡树是如何维持平衡的呢?容易想到,在建立包含一个序列中的数字的树时,如果能够随机选择元素插入的次序,那么所建立的树应当是接近平衡的,而由于我们建立的树需要支持插入,删除等操作,因此需要在每个节点建立时随机选择一个平衡因子,在之后的操作中维持树上的平衡因子最小堆或最大堆的性质,这样就可以实现期望平衡

实现

基本操作

人如其名,分裂合并treap的核心操作就是分裂与合并。

Split

在分裂操作中,我们所做的操作是对于给定的权值k,将当前的树分裂为权值大于k和小于等于k两部分。

void split(int now,int k,int &x,int &y)\\x,y分别表示当前权值小于等于k的子树的根节点和大权值大于k的子树的根节点
{
    if(!now)x=y=0;//若已经搜索到树叶,则直接返回
    else 
    {
        if(val[now]<=k)
            x=now,split(ch[now][1],k,ch[now][1],y);//如果当前节点的权值小于等于k,则小于等于k的子树的根节点即为当前节点,同时继续遍历右子树
        else 
            y=now,split(ch[now][0],k,x,ch[now][0]);//同上
        update(now);
    }
}

Merge

在合并操作中,所做的操作是对于两棵树x,y(x中所有节点的权值小于y中所有结点的权值

int merge(int x,int y)//y中的所有权值大于x中的权值
{
    if(!x||!y)return x+y;//如果需要合并的一个树为空,则直接返回另一个待合并树
    else 
    {
        if(pri[x]<pri[y])//维护平衡因子小根堆性质
            {
                ch[x][1]=merge(ch[x][1],y);//将y与x右子树合并
                update(x);return x;
            }
        else
            {
                ch[y][0]=merge(x,ch[y][0]);//将x与y左子树合并
                update(y);return y;
            }
    }
}

题目实现

基本操作讲完了,接下来要做
的就是通过这两种操作来实现题目要求的各种功能。

Insert

在插入操作中,对于需要插入的x,为了满足merge操作中需要合并的两个树权值所满足的性质,我们首先将原树分裂为大于x和小于等于x两个部分,在将x与两者依次合并

void insert(int v)
{
    int x,y;
    split(root,v,x,y);
    root=merge(merge(x,new_node(v))),y);
}

Delete

删除权值为v的点,把树按照v分成两个a,b,再把a按照v-1分成c,d。把c的两个子树合并起来,再将得到的三个树依次合并

void del(int v)
{
    int x,y,z;
    split(root,v,x,z);
    split(x,v-1,x,y);
    y=merge(ch[y][0],ch[y][1]);
    root=merge(merge(x,y),z);
}

Rank

将原树分裂为大于v-1和小于等于v-1两个部分,将小于等于v-1的子树元素数量加一即为排名

int rank(int v)
{
    int x,y;
    split(root,v-1,x,y);
    int rank=size[x]+1;
    root=merge(x,y);
    return rank;
}

前驱,后驱和排名和普通二叉搜索树类似,略

完整代码

#include<ctime>
#include<cstdlib>
#include<iostream>

using namespace std;

const int N=500005;

int val[N],ch[N][2],pri[N],siz[N],sz,root;



void update(int now)
{
    size[now]=size[ch[now][0]]+size[ch[now][1]]+1;
}

int new_node(int v)
{
    size[++sz]=1;
    val[sz]=v;
    pri[sz]=rand();
    return sz;
}

void split(int now,int k,int &x,int &y)
{
    if(!now)x=y=0;
    else 
    {
        if(val[now]<=k)
            x=now,split(ch[now][1],k,ch[now][1],y);
        else 
            y=now,split(ch[now][0],k,x,ch[now][0]);
        update(now);
    }
}

int merge(int x,int y)//y中的所有权值大于x中的权值
{
    if(!x||!y)return x+y;
    else 
    {
        if(pri[x]<pri[y])
            {
                ch[x][1]=merge(ch[x][1],y);
                update(x);return x;
            }
        else
            {
                ch[y][0]=merge(x,ch[y][0]);
                update(y);return y;
            }
    }
}

void insert(int v)
{
    int x,y;
    split(root,v,x,y);
    root=merge(merge(x,new_node(v))),y);
}

void del(int v)
{
    int x,y,z;
    split(root,v,x,z);
    split(x,v-1,x,y);
    y=merge(ch[y][0],ch[y][1]);
    root=merge(merge(x,y),z);
}

int rank(int v)
{
    int x,y;
    split(root,v-1,x,y);
    int rank=size[x]+1;
    root=merge(x,y);
    return rank;
}

int kth(int k)
{
    while(true)
    {
        if(k<=size[ch[now][0]])
            now=ch[now][0];
        else if(k==size[ch[now][0]]+1)
            return now;
        else
            k-=size[ch[now][0]]+1,now=ch[now][1];
    }
}


int precursor(int v)
{
    int x,y;
    split(root,v-1,x,y);
    int ans=val[kth(x,size[x])];
    root=merge(x,y);
    return ans;
}

int successor(int v)
{
    int x,y;
    split(root,v,x,y);
    int ans=val[kth(y,1)];
    root=merge(x,y);
    return ans;
}

int main()
{
    int T,v,opt;
    srand((unsigned)time(NULL));
    cin>>T;
    while(T--)
    {
        cin>>v>>opt;
        if(opt==1)
            insert(v);
        else if(opt==2)
            del(v);
        else if(opt==3)
            cout<<rank(v)<<endl;
        else if(opt==4)
            cout<<val[kth(root,v)]<<endl;
        else if(opt==5)
            cout<<precursor(v)<<endl;
        else if(opt==6)
            cout<<successor(v)<<endl;
    }
}

举报

相关推荐

0 条评论