题目:

http://www.lydsy.com/JudgeOnline/problem.php?id=3224

题意:

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每行输出一个数,表示对应答案

思路:

通常平衡树不支持树里有相同值,这里增加一个num属性记录相同值的个数

#include <bits/stdc++.h>

using namespace std;

const int N = 100000 + 10;

struct node
{
    int val, pri, son[2];
    int sz, 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)
    {
        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)
    {
        //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)
    {
        //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;
}