平衡树 fhqTreap

//Treap fhq版(不旋转) 
//所有操作依靠split()(分离)和merge()(合并)完成 
//可支持区间操作和可持久化 比普通Treap更通用 
//所有Treap中序遍历均为递增序列 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
using namespace std;
int n,cnt,size,root,x,y,z;
//x为小Treap的根节点 y为中Treap的根节点 z为大Treap的根节点 root为总Treap的根节点 
int son[100001][2],siz[100001],val[100001],rd[100001];
//左右儿子,子树大小+自己大小,点值,随机权值 
int new_node(int m)//建立新节点 
{
    siz[++size]=1;
    val[size]=m;
    rd[size]=rand();
    return size;
}
void update(int now)
{
    siz[now]=siz[son[now][0]]+siz[son[now][1]]+1;
}
void split(int now,int k,int &a,int &b)
{
    if(!now)
    {
        a=b=0;
        return;
    }
    if(val[now]<=k)
        a=now,split(son[now][1],k,son[now][1],b);
        //将此节点及其左子树接到小Treap上,并遍历此节点的右节点 
    else b=now,split(son[now][0],k,a,son[now][0]);
        //将此节点及其右子树接到大Treap上,并遍历此节点的左节点 
    update(now);
}
int merge(int a,int b)
{
    if(!a||!b)
        return a+b;
    if(rd[a]<rd[b])
    {
        son[a][1]=merge(son[a][1],b);
        //将小Treap节点及其左子树接在总Treap上,并遍历此节点的右节点 
        update(a);
        return a; 
    }
    else
    {
        son[b][0]=merge(a,son[b][0]);
        //将大Treap节点及其右子树接在总Treap上,并遍历此节点的左节点 
        update(b);
        return b;
    }
}
int k_th(int now,int k)
{
    while(1)
    {
        if(k<=siz[son[now][0]])
            now=son[now][0];
        else if(k==siz[son[now][0]]+1)
            return now;
        else
        {
            k-=siz[son[now][0]]+1;
            now=son[now][1];
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u,k;
        scanf("%d%d",&u,&k);
        if(u==1)//插入 
        {
            split(root,k,x,z);//先分成两个Treap 此时k(若有)在小Treap中 
            root=merge(merge(x,new_node(k)),z);//重新合并 
        }
        if(u==2)//删除 
        {
            split(root,k,x,z);//先分成两个Treap 此时k在小Treap中 
            split(x,k-1,x,y);//再把小Treap分成两个Treap 此时k在中Treap中 且为中Treap根节点 
            y=merge(son[y][0],son[y][1]);//把中Treap根节点的两个子树合并 此时已删除k 
            root=merge(merge(x,y),z);//重新合并 
        }
        if(u==3)//查找权值为k的排名
        {
            split(root,k-1,x,z);//先分成两个Treap 此时小Treap中包含了所有小于k的数 
            printf("%d\n",siz[x]+1);//k的排名即为小于k的权值数目+1 
            root=merge(x,z);//重新合并 
        }
        if(u==4)//查找排名为k的权值 
            printf("%d\n",val[k_th(root,k)]);//直接输出 
        if(u==5)//求前驱 
        {
            split(root,k-1,x,z);//先分成两个Treap 此时k是大Treap中最小的数 
            printf("%d\n",val[k_th(x,siz[x])]);//前驱即为小Treap中最大的数 即最右节点 
            root=merge(x,z);//重新合并 
        }
        if(u==6)//求后继 
        {
            split(root,k,x,z);//先分成两个Treap 此时k是小Treap中最大的数 
            printf("%d\n",val[k_th(z,1)]);//后继即为大Treap中最小的数 即最左节点 
            root=merge(x,z);//重新合并 
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/water-radish/p/9280878.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值