Tyvj 1728 普通平衡树 HYSBZ - 3224 Treap树模板

题目链接:https://vjudge.net/problem/HYSBZ-3224
转自:https://blog.csdn.net/qq_39897867/article/details/99719484
模板:https://blog.csdn.net/Roll_Keyboard/article/details/81045891
讲解:https://blog.csdn.net/yandaoqiusheng/article/details/85037548

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
struct Treap
{
    int l,r;        //左,右
    int val,dat;    //价值,随机值
    int cnt,sz;   //副本数,子树大小
} t[N];
int tot,root,n,INF = 0x7fffffff;

void init()
{
    tot=0;
}
int New(int val)
{
    t[++tot].val=val;
    t[tot].dat=rand();
    t[tot].l=t[tot].r=0;
    t[tot].cnt=t[tot].sz=1;
    return tot;
}
void update(int p)//统计子节点数
{
    t[p].sz=t[t[p].l].sz+t[t[p].r].sz+t[p].cnt;
}
void build()
{
    New(-INF);
    New(INF);
    root=1,t[1].r=2;
    update(root);
}
void zig(int &p)//旋转操作
{
    int q=t[p].l;
    t[p].l=t[q].r,t[q].r=p,p=q;
    update(t[p].r),update(p);
}
void zag(int &p)//旋转操作
{
    int q=t[p].r;
    t[p].r=t[q].l,t[q].l=p,p=q;
    update(t[p].l),update(p);
}

void Insert(int &p,int val)                 //插入
{
    if(p==0)//到达空节点
    {
        p=New(val);
        return ;
    }
    if(val==t[p].val)
    {
        t[p].cnt++,update(p);
        return ;
    }
    if(val<t[p].val)
    {
        Insert(t[p].l,val);
        if(t[p].dat<t[t[p].l].dat)
            zig(p);
    }
    else
    {
        Insert(t[p].r,val);
        if(t[p].dat<t[t[p].r].dat)
            zag(p);
    }
    update(p);
}

void Remove(int &p,int val)         //删除
{
    if(p==0)
        return ;
    if(val==t[p].val)
    {
        if(t[p].cnt>1)
        {
            t[p].cnt--,update(p);
            return ;
        }
        if(t[p].l||t[p].r)
        {
            if(t[p].r==0||t[t[p].l].dat>t[t[p].r].dat)
                zig(p),Remove(t[p].r,val);
            else
                zag(p),Remove(t[p].l,val);
            update(p);
        }
        else
            p=0;
        return ;
    }
    val<t[p].val?Remove(t[p].l,val):Remove(t[p].r,val);
    update(p);
}

int GetRankByVal(int p,int val)        //排名(记得减1,因为有-inf)
{
    if(p==0)
        return 0;
    if(val==t[p].val)
        return t[t[p].l].sz+1;//注意这个地方
    if(val<t[p].val)
        return GetRankByVal(t[p].l,val);
    return GetRankByVal(t[p].r,val)+t[t[p].l].sz+t[p].cnt;
}

int GetValByRank(int p,int rnk)        //排名为rnk的数(rnk记得加1,因为有-inf)
{
    if(p==0)
        return INF;
    if(t[t[p].l].sz>=rnk)
        return GetValByRank(t[p].l,rnk);
    if(t[t[p].l].sz+t[p].cnt>=rnk)
        return t[p].val;
    return GetValByRank(t[p].r,rnk-t[t[p].l].sz-t[p].cnt);
}

int GetPre(int val)             //前驱 小于val的最大数
{
    int ans=1;
    int p=root;
    while(p)
    {
        if(val==t[p].val)
        {
            if(t[p].l>0)
            {
                p=t[p].l;
                while(t[p].r>0)
                    p=t[p].r;
                ans=p;
            }
            break;
        }
        if(t[p].val<val&&t[p].val>t[ans].val)
            ans=p;
        p=val<t[p].val?t[p].l:t[p].r;
    }
    return t[ans].val;
}

int GetNext(int val)        //后继
{
    int ans=2;
    int p=root;
    while(p)
    {
        if(val==t[p].val)
        {
            if(t[p].r>0)
            {
                p=t[p].r;
                while(t[p].l>0)
                    p=t[p].l;
                ans=p;
            }
            break;
        }
        if(t[p].val>val&&t[p].val<t[ans].val)
            ans=p;
        p=val<t[p].val?t[p].l:t[p].r;
    }
    return t[ans].val;
}


int main()
{
    int n;
    scanf("%d",&n);
    build();
    for(int i=0; i<n; i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a==1)
        {
            Insert(root,b);
        }
        else if(a==2)
        {
            Remove(root,b);
        }
        else if(a==3)
        {
            printf("%d\n",GetRankByVal(root,b)-1);
        }
        else if(a==4)
        {
            printf("%d\n",GetValByRank(root,b+1));
        }
        else if(a==5)
        {
            printf("%d\n",GetPre(b));
        }
        else
        {
            printf("%d\n",GetNext(b));
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值