Splay 样例过不了求调
查看原帖
Splay 样例过不了求调
726139
残阳如血楼主2024/9/8 21:34
#include <bits/stdc++.h>
// const int N = 1e5 + 10;
const int N = 12;

struct Splay {
  int root, tot, val[N], siz[N], cnt[N], fa[N], son[N][2];

  void pushup(int x) { // 合并 x 的左儿子与右儿子,得到 x 的大小
    siz[x] = siz[son[x][0]] + siz[son[x][1]] + cnt[x];
  }

  bool get(int x) { // get(x)=1 说明 x 是右儿子,反之是左儿子
    return x == son[fa[x]][1];
  }

  void clear(int x) { // 销毁结点 x
    son[x][0] = son[x][1] = fa[x] = val[x] = siz[x] = cnt[x] = 0;
  }

  void rotate(int x) {
    int y = fa[x], z = fa[y];
    int id = get(x); // 判断 x 是 y 的左儿子还是右儿子
    son[z][get(y)] = x, fa[x] = z;
    son[y][id] = son[x][id ^ 1], fa[son[x][id ^ 1]] = y;
    son[x][id ^ 1] = y, fa[y] = x;
    pushup(y), pushup(x);
  }

  void splay(int x, int k) { // 将 x 转到 k 的下面
    while (fa[x] != k) {
      int y = fa[x], z = fa[y];
      if (z != k) {
        if (get(x) ^ get(y)) rotate(x);
        else rotate(y);
      }
      rotate(x);
    }
    if (!k) root = x;
  }

  void insert(int k) {
    if (!root) { // 树为空
      val[++tot] = k;
      ++cnt[tot];
      pushup(root = tot);
      return ;
    }
    int x = root, y = 0;
    while (true) {
      if (val[x] == k) { // 找到目标
        ++cnt[x];
        pushup(x), pushup(y);
        splay(x, 0);
        break;
      }
      y = x, x = son[x][val[x] < k];
      if (!x) { // 插入新结点
        val[++tot] = k;
        ++cnt[tot];
        fa[tot] = y;
        son[y][val[y] < k] = tot;
        pushup(tot);
        pushup(y);
        splay(tot, 0);
        break;
      }
    }
  }

  int get_rank(int k) { // 查询 k 的排名
    int res = 0, x = root;
    while (true) {
      if (k < val[x]) x = son[x][0]; // k 落在 x 的左子树
      else {
        res += siz[son[x][0]];
        if (!x) return res + 1;
        if (val[x] == k) return splay(x, 0), res + 1;
        res += cnt[x], x = son[x][1];
      }
    }
    return -1;
  }

  int get_kth(int k) { // 查询排名为 k 的数
    int x = root;
    while (true) {
      if (son[x][0] && k <= siz[son[x][0]]) x = son[x][0];
      else {
        k -= cnt[x] + siz[son[x][0]];
        if (k <= 0) return splay(x, 0), val[x];
        x = son[x][1];
      }
    }
    return -1;
  }

  int get_pre() { // 查询根节点的前驱
    int x = son[root][0];
    while (son[x][1]) x = son[x][1];
    splay(x, 0);
    return x;
  }

  int get_nxt() { // 查询根节点的后继
    int x = son[root][1];
    while (son[x][0]) x = son[x][0];
    splay(x, 0);
    return x;
  }

  void erase(int k) { // 删除一个权值为 k 的数
    get_rank(k);
    if (cnt[root] > 1) {
      --cnt[root];
      pushup(root);
      return ;
    }
    if (!son[root][0] && son[root][1]) { // 树中只有一个根结点
      clear(root);
      root = 0;
      return ;
    }
    if (!son[root][0]) { // 左子树为空
      int cur = root;
      fa[root = son[root][1]] = 0;
      clear(cur);
    }
    if (!son[root][1]) { // 右子树为空
      int cur = root;
      fa[root = son[root][0]] = 0;
      clear(cur);
    }
    int cur = root, x = get_pre();
    fa[son[cur][1]] = x;
    son[x][1] = son[cur][1];
    clear(cur);
    pushup(root);
  }
} tree;

int main() {
  int n, op, x;
  for (scanf("%d", &n); n; --n) {
    scanf("%d%d", &op, &x);
    if (op == 1) tree.insert(x);
    else if (op == 2) tree.erase(x);
    else if (op == 3) printf("%d\n", tree.get_rank(x));
    else if (op == 4) printf("%d\n", tree.get_kth(x));
    else if (op == 5) tree.insert(x), printf("%d\n", tree.get_pre()), tree.erase(x);
    else tree.insert(x), printf("%d\n", tree.get_nxt()), tree.erase(x);
  }
  return 0;
}
2024/9/8 21:34
加载中...