BZOJ 3224: Tyvj 1728 普通平衡树

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input

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

对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
10

1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

Sample Output
106465

84185

492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-1e7,1e7]

数据如下http://pan.baidu.com/s/1jHMJwO2

解题方法: multi_treap裸题,记录模板。treap是一棵修改了结点顺序的二叉查找树

通常树内的每个结点x都有一个关键字值key[x],另外,还要为结点分配一个随机数。

假设所有的优先级是不同的,所有的关键字也是不同的。treap的结点排列成让关键字遵循二叉查找树性质,并且优先级遵

循最小堆顺序性质:
1.如果v是u的左孩子,则key[v] < key[u].
2.如果v是u的右孩子,则key[v] > key[u].
3.如果v是u的孩子,则rand[u] > rand[u].
这两个性质的结合就是为什么这种树被称为“treap”的原因,因为它同时具有二叉查找树和heap的特征。

#include <bits/stdc++.h>
using namespace std;
namespace multi_treap{
    struct data{
        int l, r, v, size, rnd, w;
    }tree[100005];
    int n, size, root, ans;
    void update(int k)
    {
        tree[k].size = tree[tree[k].l].size + tree[tree[k].r].size + tree[k].w;
    }
    void rturn(int &k)
    {
        int t = tree[k].l;
        tree[k].l = tree[t].r;
        tree[t].r = k;
        tree[t].size = tree[k].size;
        update(k);
        k = t;
    }
    void lturn(int &k)
    {
        int t = tree[k].r;
        tree[k].r = tree[t].l;
        tree[t].l = k;
        tree[t].size = tree[k].size;
        update(k);
        k=t;
    }
    void insert(int &k, int x)
    {
        if(k == 0)
        {
            size++;
            k = size;
            tree[k].size = tree[k].w = 1;
            tree[k].v = x;
            tree[k].rnd = rand();
            return ;
        }
        tree[k].size++;
        if(tree[k].v==x) tree[k].w++;//每个结点顺便记录下与该节点相同值的数的个数
        else if(x > tree[k].v)
        {
            insert(tree[k].r, x);
            if(tree[tree[k].r].rnd < tree[k].rnd) lturn(k);//维护堆性质
        }
        else
        {
            insert(tree[k].l, x);
            if(tree[tree[k].l].rnd < tree[k].rnd) rturn(k);
        }
    }
    void del(int &k,int x)
    {
        if(k == 0)return;
        if(tree[k].v == x)
        {
            if(tree[k].w > 1)
            {
                tree[k].w--;
                tree[k].size--;
                return;//若不止相同值的个数有多个,删去一个
            }
            if(tree[k].l * tree[k].r == 0)k = tree[k].l + tree[k].r;//有一个儿子为空
            else if(tree[tree[k].l].rnd < tree[tree[k].r].rnd)
                rturn(k),del(k,x);
            else lturn(k),del(k,x);
        }
        else if(x > tree[k].v)
            tree[k].size--, del(tree[k].r,x);
        else tree[k].size--, del(tree[k].l,x);
    }
    int query_rank(int k, int x)
    {
        if(k == 0) return 0;
        if(tree[k].v == x) return tree[tree[k].l].size + 1;
        else if(x > tree[k].v)
            return tree[tree[k].l].size + tree[k].w + query_rank(tree[k].r, x);
        else return query_rank(tree[k].l, x);
    }
    int query_num(int k, int x)
    {
        if(k == 0) return 0;
        if(x <= tree[tree[k].l].size)
            return query_num(tree[k].l, x);
        else if(x > tree[tree[k].l].size + tree[k].w)
            return query_num(tree[k].r,x - tree[tree[k].l].size-tree[k].w);
        else return tree[k].v;
    }
    void query_pro(int k, int x)
    {
        if(k == 0)return;
        if(tree[k].v < x)
        {
            ans = k;
            query_pro(tree[k].r, x);
        }
        else query_pro(tree[k].l, x);
    }
    void query_sub(int k, int x)
    {
        if(k == 0)return;
        if(tree[k].v > x)
        {
            ans = k;
            query_sub(tree[k].l, x);
        }
        else query_sub(tree[k].r, x);
    }
}
int main()
{
    using namespace multi_treap;
    int op, n, x;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d", &op, &x);
        switch(op)
        {
        case 1:insert(root, x); break;
        case 2:del(root, x); break;
        case 3:printf("%d\n", query_rank(root, x)); break;
        case 4:printf("%d\n", query_num(root, x)); break;
        case 5: ans = 0; query_pro(root, x); printf("%d\n", tree[ans].v); break;
        case 6: ans = 0; query_sub(root, x); printf("%d\n", tree[ans].v); break;
        }
    }
    return 0;
}

还有就是这个题除了multi_treap,直接用vector也是可以过的,因为实际上vector的插入是O(sqrt(n))的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值