平衡树treap模板

洛谷 P3369 【模板】普通平衡树(Treap/SBT)

1.插入x数

2.删除x数(若有多个相同的数,因只删除一个)

3.查询x数的排名(若有多个相同的数,因输出最小的排名)

4.查询排名为x的数

5.求x的前驱(前驱定义为小于x,且最大的数)

6.求x的后继(后继定义为大于x,且最小的数)

输入输出格式 

输入格式:

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 100000 + 10;



struct node//定义节点信息

{

    //保证父亲的pri大于儿子的pri,pri应该是优先级

    int val, pri, son[2];

    //sz表示子树的大小

    int sz, num;//平衡树不支持多个相同值的点,我们多加一个num来计数

    void init(int _val, int _pri, int _sz, int _num)

    {

        val = _val, pri = _pri, sz = _sz, num = _num;

        son[0] = son[1] = 0;

    }

};

struct Treap//定义平衡树

{

    int tot, root;

    int pro, sub;

    node tr[N];

    void init()

    {

        tot = 0, root = 0;

        tr[0].init(0, 0, 0, 0);

    }

    void update(int x)//更新size树的大小信息

    {

        tr[x].sz = tr[tr[x].son[0]].sz + tr[tr[x].son[1]].sz + tr[x].num;

    }

    void rotate(int &x, int p)//p=0左旋,p=1右旋

    {

        int y = tr[x].son[!p];

        tr[x].son[!p] = tr[y].son[p];

        tr[y].son[p] = x;

        update(x); update(y);//必须先更新x后更新y

        x = y;

    }

    void insert(int &x, int val)//插入数值

    {

        if(x == 0) tr[x = ++tot].init(val, rand(), 1, 1);

        else

        {

            tr[x].sz++;

            if(tr[x].val == val)

            {

                tr[x].num++; return;

            }

            int p = val > tr[x].val;

            insert(tr[x].son[p], val);

            if(tr[x].pri < tr[tr[x].son[p]].pri) rotate(x, !p);

        }

    }

    void del_node(int &x, int val)//删除节点

    {

        //if(x == 0) return;

        if(tr[x].val == val)

        {

            if(tr[x].num > 1)

            {

                tr[x].sz--; tr[x].num--; return;

            }

            if(tr[x].son[0] && tr[x].son[1])

            {

                int p = tr[tr[x].son[0]].pri > tr[tr[x].son[1]].pri;

                rotate(x, p);

                tr[x].sz--;//如果接下删除tr[x].son[p],注意处理tr[x].sz,因为这个一直TLE

                del_node(tr[x].son[p], val);

                //del_node(x, val); //注释掉的写法不用处理sz的问题,因为递归到下一层会处理

            }

            else

            {

                //x = tr[x].son[0] + tr[x].son[1];  //合并,很凝炼

                if(tr[x].son[0] != 0) x = tr[x].son[0];

                else x = tr[x].son[1];

            }

        }

        else

        {

            int p = val > tr[x].val;

            tr[x].sz--;

            del_node(tr[x].son[p], val);

        }

    }

    int get_kth(int x, int k) //得到排名K的数字

    {

        //if(x == 0) return 0;

        if(k > tr[tr[x].son[0]].sz + tr[x].num) return get_kth(tr[x].son[1], k - tr[tr[x].son[0]].sz - tr[x].num);

        else if(k <= tr[tr[x].son[0]].sz) return get_kth(tr[x].son[0], k);

        else return tr[x].val;

    }

    int get_rank(int x, int val)//得到数值val的排名

    {

        //if(x == 0) return 0;

        if(val == tr[x].val) return tr[tr[x].son[0]].sz + 1;

        else if(val > tr[x].val) return get_rank(tr[x].son[1], val) + tr[tr[x].son[0]].sz + tr[x].num;

        else return get_rank(tr[x].son[0], val);

    }

    void get_pro(int x, int val) //得到前驱的值

    {

        if(x == 0) return;

        if(tr[x].val < val)

        {

            pro = tr[x].val; get_pro(tr[x].son[1], val);

        }

        else get_pro(tr[x].son[0], val);

    }

    void get_sub(int x, int val) //得到后继的值

    {

        if(x == 0) return;

        if(tr[x].val > val)

        {

            sub = tr[x].val; get_sub(tr[x].son[0], val);

        }

        else get_sub(tr[x].son[1], val);

    }

}treap;

int main()

{

    int n, op, val;

    scanf("%d", &n);

    treap.init();//初始化

    for(int i = 1; i <= n; i++)

    {

        scanf("%d%d", &op, &val);

        if(op == 1) treap.insert(treap.root, val);//把值加进去

        else if(op == 2) treap.del_node(treap.root, val);

        else if(op == 3) printf("%d\n", treap.get_rank(treap.root, val));

        else if(op == 4) printf("%d\n", treap.get_kth(treap.root, val));

        else if(op == 5) treap.pro = 0, treap.get_pro(treap.root, val), printf("%d\n", treap.pro);

        else if(op == 6) treap.sub = 0, treap.get_sub(treap.root, val), printf("%d\n", treap.sub);

    }

    return 0;

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值