[平衡树模板]Treap

算法标签 Treap

种下第一棵平衡树…

题目描述 Description

这是一道模板题。

如果觉得这个题水的可以做一下4544压行,是千古神犇花爸爸出的神犇题。

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

输入描述 Input Description

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

输出描述 Output Description

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

注意:这道题重复数据可以加入Treap

#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 100005;
struct node {
    node *ch[2];
    int r, v, s; //v-键值 r-优先级 s - 子树结点个数
    inline int cmp(int x) const {
      return x < v ? 0 : 1;
    }
    inline void maintain() { //计算子结点个数
      s = 1;
      if(ch[0] != NULL) s += ch[0] -> s;
      if(ch[1] != NULL) s += ch[1] -> s;
    }
};

void retate(node* &x, int d) //旋转, d = 0 左旋 d = 1 右旋
{
    node *k = x -> ch[d ^ 1];
    x->ch[d ^ 1] = k -> ch[d]; k->ch[d] = x;
    x->maintain(); k->maintain(); //重新计算子结点个数
    x = k;
}

void insert(node* &x, int k) //在以x为根的子树中插入键值k,修改x
{
    if(x == NULL) {x = new node(); x -> ch[0] = x -> ch[1] = NULL; x -> v = k; x -> r = rand(); x -> s = 1; }//x为空
    else {
      int d = x -> cmp(k);
      insert(x -> ch[d], k); if(x -> ch[d] -> r > x -> r) retate(x, d ^ 1); 
    }
    x -> maintain();
}

void remove(node* &x, int k) //在以x为根的子树中删除键值k,修改x
{
    if(x -> v == k) { //k = x.v
      if(x -> ch[0] == NULL) x = x -> ch[1]; //左子树为空
      else if(x -> ch[1] == NULL) x = x -> ch[0]; //右子树为空
      else {
        int d = (x -> ch[0] -> r > x -> ch[1] -> r ? 1 : 0);
        retate(x, d); remove(x -> ch[d], k); //递归删除
      }
    }else remove(x -> ch[x -> cmp(k)], k);
    if(x != NULL) x -> maintain();
}

int Rank(node *x, int k) //查找k的排名
{
    if(x == NULL) return 1;
    if(k <= x -> v) return Rank(x ->ch[0], k);
    else return Rank(x -> ch[1], k) + (x -> ch[0] != NULL ? x -> ch[0] -> s : 0) + 1; 
}

int kth(node *x, int k) //查找第k小元素
{
    if(x == NULL || k <= 0 || k > x -> s) return 0;
    int s = (x -> ch[0] == NULL ? 0 : x -> ch[0] -> s);
    if(s + 1 == k) return x -> v;
    else if(k <= s) return kth(x -> ch[0], k);
    else return kth(x -> ch[1], k - s - 1);
}

int last(node *x, int k) //求k的前驱
{
    if(x == NULL) return -(1 << 30);
    if(x -> v < k) return max(x -> v, last(x -> ch[1], k));
    else return last(x -> ch[0], k);
}

int next(node *x, int k) //求k的后继
{
    if(x == NULL) return (1 << 30);
    if(x -> v > k) return min(x -> v, next(x -> ch[0], k));
    else return next(x -> ch[1], k);
}

int main()
{
    freopen("phs.in", "r", stdin);
    freopen("phs.out", "w", stdout);
    int cnt = 0, n; scanf("%d", &n);
    node *root = NULL;
    for(int x, opt, i = 1; i <= n; ++i) {
      scanf("%d%d", &opt, &x);
      if(opt == 1) insert(root, x);
      else if(opt == 2) remove(root, x);
      else if(opt == 3) printf("%d\n", Rank(root, x));
      else if(opt == 4) printf("%d\n", kth(root, x));
      else if(opt == 5) printf("%d\n", last(root, x));
      else if(opt == 6) printf("%d\n", next(root, x));
    }
    return 0;
}

你可能感兴趣的:(文章类型——学习笔记)