仅70行的带旋treap求调(65pts),代码清晰,附有注释
查看原帖
仅70行的带旋treap求调(65pts),代码清晰,附有注释
286239
ql12345楼主2024/11/13 20:34
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct Treap {
private :
    int nodecnt, pool[N], poolcnt, root;
    int son[N][2], val[N], prio[N], cnt[N], siz[N];
    void init() { nodecnt = poolcnt = root = son[0][0] = son[0][1] = prio[0] = siz[0] = 0; }
    void pushup(int cur) { siz[cur] = siz[son[cur][0]] + siz[son[cur][1]] + 1; }
    void newnode(int& cur, int x) {
        cur = poolcnt ? pool[poolcnt --] : ++ nodecnt;
        son[cur][0] = son[cur][1] = 0, val[cur] = x, prio[cur] = rand(), cnt[cur] = siz[cur] = 1;
    }
    void rotate(int& cur, int f) { // 以 cur 为根的子树旋转并把 cur 更新为新的根节点编号,f 为 0 表示左旋
        int t = son[cur][f ^ 1];
        son[cur][f ^ 1] = son[t][f], son[t][f] = cur, pushup(cur), pushup(t), cur = t;
    }
    void insert(int& cur, int x) { // x 存在则找到 x 的位置 cnt ++,否则找到要插入的叶节点的位置
        if (! cur) return newnode(cur, x);
        if (x == val[cur]) return cnt[cur] ++, siz[cur] ++, void(); // cnt ++ 即可
        int f = x > val[cur];
        insert(son[cur][f], x), pushup(cur);
        if (prio[son[cur][f]] > prio[cur]) rotate(cur, f ^ 1); // 回溯的时候顺便向上调整维护堆
    }
    void remove(int& cur, int x) { // x 存在且 cnt > 1 则 cnt --,否则将要删除的点移到叶节点删除
        if (! (son[cur][0] | son[cur][1])) { // 到叶节点自动删除
            if (cur) pool[++ poolcnt] = cur;
            return cur = 0, void();
        }
        if (x == val[cur] && cnt[cur] > 1) cnt[cur] --, siz[cur] --; // cnt -- 即可
        else if (x == val[cur]) { // 将当前节点移到叶节点
            int f = prio[son[cur][1]] > prio[son[cur][0]];
            rotate(cur, f ^ 1), remove(son[cur][f ^ 1], x), pushup(cur);
        }
        else remove(son[cur][x > val[cur]], x), pushup(cur); // 继续往下找
    }
    int rank(int cur, int x) { // cur 为根的子树内比 x 小的数的个数
        if (! cur) return 0;
        if (x == val[cur]) return siz[son[cur][0]];
        if (x < val[cur]) return rank(son[cur][0], x);
        return siz[son[cur][0]] + cnt[cur] + rank(son[cur][1], x);
    }
    int kth(int cur, int k) { // cur 为根的子树内排名为 k 的数
        if (siz[cur] < k || k <= 0) return -1;
        if (k <= siz[son[cur][0]]) return kth(son[cur][0], k);
        if (k <= siz[son[cur][0]] + cnt[cur]) return val[cur];
        return kth(son[cur][1], k - siz[son[cur][0]] - cnt[cur]);
    }
public :
    void ins(int x) { insert(root, x); }
    void rem(int x) { remove(root, x); }
    int ran(int x) { return rank(root, x) + 1; }
    int kth(int k) { return kth(root, k); }
    int pre(int x) { return kth(ran(x) - 1); } // 最大的比 x 小的数
    int nxt(int x) { return kth(ran(x + 1)); } // 最小的比 x 大的数
} treap;
int main() {
    srand(time(0));
    int n; scanf("%d", &n);
    for (int i = 1, op, x; i <= n; i ++) {
        scanf("%d%d", &op, &x);
        if (op == 1) treap.ins(x);
        else if (op == 2) treap.rem(x);
        else if (op == 3) printf("%d\n", treap.ran(x));
        else if (op == 4) printf("%d\n", treap.kth(x));
        else if (op == 5) printf("%d\n", treap.pre(x));
        else if (op == 6) printf("%d\n", treap.nxt(x));
    }
    return 0;
}

有错的地方应该是 siz 的维护

2024/11/13 20:34
加载中...