treap树(平衡树的其他版本)

\(Treap\) 树性质

具有 \(BST\) 树的二叉搜索性质,又具有堆的性质,从而保证树不退化成一颗链,保证操作都是 \(log\) 级别的。

std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());

struct node{
    int val;// 这个数的值
    int prq;// 这个数的随机值用来维护堆的性质(大根堆或小根堆)
    int siz;// 以这个点为根的子树大小
    int cnt;// 多少个这样相同的值
    int ch[2];// 左右儿子
    node(int val = 0, int prq = 0, int siz = 0, int cnt = 0) : val(val), prq(prq), siz(siz), cnt(cnt) {
        ch[0] = ch[1] = 0;
    }
} tree[N + 1];
int tot;

// 维护
inline void push_up(int p) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    tree[p].siz = tree[ls].siz + tree[rs].siz + tree[p].cnt;
}

// 左右旋
void rotate(int &p, int op) {// op为0表示左旋,op为1表示右旋
    int k = tree[p].ch[op ^ 1];
    tree[p].ch[op ^ 1] = tree[k].ch[op];
    tree[k].ch[op] = p;
    push_up(p);// 先维护儿子节点p
    push_up(k);// 再维护父亲节点k
    p = k;// 根节点变成了k
}

// 插入
inline void ins(int &p, int val) {
    if (!p) {
        p = ++tot;
        tree[p] = node(val, rng() % mof, 1, 1);
        return;
    }
    if (tree[p].val == val) {
        tree[p].cnt++;
        tree[p].siz++;
        return;
    }
    int op = val > tree[p].val;
    int &k = tree[p].ch[op];
    ins(k, val);
    if (tree[p].prq < tree[tree[p].ch[op]].prq) {
        rotate(p, op ^ 1);
    }
    push_up(p);
}

// 删除
inline void del(int &p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return;
    if (tree[p].val > val) {
        del(ls, val);
    } else if (tree[p].val < val) {
        del(rs, val);
    } else {
        if (!ls && !rs) {// 说明是叶子结点,直接删除
            tree[p].siz--;
            tree[p].cnt--;
            if (tree[p].cnt == 0) {
                p = 0;
            }
        } else if (ls && !rs) {// 将他右旋直到转移到叶子结点上
            rotate(p, 1);
            del(tree[p].ch[1], val);
        } else if (!ls && rs) {// 将他左旋直到转移到叶子结点上
            rotate(p, 0);
            del(tree[p].ch[0], val);
        } else if (ls && rs) {// 左右子树都不为空,找到左子树中最大值或右子树中最小值,然后删除
            int d = (tree[ls].prq > tree[rs].prq);
            rotate(p, d);
            del(tree[p].ch[d], val);
        }
    }
    push_up(p);
}

// 查询某个值的排名
inline int rnk(int p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return 1;
    if (tree[p].val == val) return tree[ls].siz + 1;
    if (tree[p].val > val) return rnk(ls, val);
    if (tree[p].val < val) return tree[ls].siz + tree[p].cnt + rnk(rs, val);
}

// 查询某个排名对应的值
inline int fnd(int p, int rk) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return 0;
    if (tree[ls].siz >= rk) {
        return fnd(ls, rk);
    } else if (tree[ls].siz + tree[p].cnt < rk) {
        return fnd(rs, rk - tree[ls].siz - tree[p].cnt);
    } else {
        return tree[p].val;
    }
}

// 查询某个数的前驱
inline int pre(int p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return -inf;
    if (tree[p].val >= val) {
        return pre(ls, val);
    } else {
        return max(tree[p].val, pre(rs, val));
    }
}

// 查询某个数的后继
inline int nxt(int p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return inf;
    if (tree[p].val <= val) {
        return nxt(rs, val);
    } else {
        return min(tree[p].val, nxt(ls, val));
    }
}

void print(int p) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (ls) print(ls);
    cout << tree[p].val << ' ';
    if (rs) print(rs);
}

void solve() {
    int n;
    cin >> n;
    int root = 0;
    for (int i = 1; i <= n; i++) {
        int op, x;
        cin >> op >> x;
        if (op == 1) {
            ins(root, x);
        } else if (op == 2) {
            del(root, x);
        } else if (op == 3) {
            cout << rnk(root, x) << '\n';
        } else if (op == 4) {
            cout << fnd(root, x) << '\n';
        } else if (op == 5) {
            cout << pre(root, x) << '\n';
        } else if (op == 6) {
            cout << nxt(root, x) << '\n';
        }
        // cout << root << '\n';
        // print(root);
        // cout << '\n';
    }
}
std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
struct node{
    int val;// 这个数的值
    int prq;// 这个数的随机值用来维护堆的性质(大根堆或小根堆)
    int siz;// 以这个点为根的子树大小
    int cnt;// 多少个这样相同的值
    int ch[2];// 左右儿子
    node(int val = 0, int prq = 0, int siz = 0, int cnt = 0) : val(val), prq(prq), siz(siz), cnt(cnt) {
        ch[0] = ch[1] = 0;
    }
} tree[N + 1];
int a[100005];
int tot;

// 维护
inline void push_up(int p) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    tree[p].siz = tree[ls].siz + tree[rs].siz + tree[p].cnt;
}

// 左右旋
void rotate(int &p, int op) {// op为0表示左旋,op为1表示右旋
    int k = tree[p].ch[op ^ 1];
    tree[p].ch[op ^ 1] = tree[k].ch[op];
    tree[k].ch[op] = p;
    push_up(p);// 先维护儿子节点p
    push_up(k);// 再维护父亲节点k
    p = k;// 根节点变成了k
}

// 插入
inline void ins(int &p, int val) {
    if (!p) {
        p = ++tot;
        tree[p] = node(val, rng() % mof, 1, 1);
        return;
    }
    if (tree[p].val == val) {
        tree[p].cnt++;
        tree[p].siz++;
        return;
    }
    int op = val > tree[p].val;
    int &k = tree[p].ch[op];
    ins(k, val);
    if (tree[p].prq < tree[tree[p].ch[op]].prq) {
        rotate(p, op ^ 1);
    }
    push_up(p);
}

// 删除
inline void del(int &p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return;
    if (tree[p].val > val) {
        del(ls, val);
    } else if (tree[p].val < val) {
        del(rs, val);
    } else {
        if (!ls && !rs) {// 说明是叶子结点,直接删除
            tree[p].siz--;
            tree[p].cnt--;
            if (tree[p].cnt == 0) {
                p = 0;
            }
        } else if (ls && !rs) {// 将他右旋直到转移到叶子结点上
            rotate(p, 1);
            del(tree[p].ch[1], val);
        } else if (!ls && rs) {// 将他左旋直到转移到叶子结点上
            rotate(p, 0);
            del(tree[p].ch[0], val);
        } else if (ls && rs) {// 左右子树都不为空,找到左子树中最大值或右子树中最小值,然后删除
            int d = (tree[ls].prq > tree[rs].prq);
            rotate(p, d);
            del(tree[p].ch[d], val);
        }
    }
    push_up(p);
}

inline int build(int *L, int n, int cc = 1000000000) {// L从0开始
    if (!n) return 0;
    int p = ++tot;
    tree[p] = node(L[n >> 1], cc - 1 - rand() % 10000, 1, 1);
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    ls = build(L, n >> 1, tree[p].prq);
    rs = build(L + (n >> 1) + 1, n - 1 - (n >> 1), tree[p].prq);
    push_up(p);
    return p;
}

// 查询某个值的排名
inline int rnk(int p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return 1;
    if (tree[p].val == val) return tree[ls].siz + 1;
    if (tree[p].val > val) return rnk(ls, val);
    if (tree[p].val < val) return tree[ls].siz + tree[p].cnt + rnk(rs, val);
}

// 查询某个排名对应的值
inline int fnd(int p, int rk) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return 0;
    if (tree[ls].siz >= rk) {
        return fnd(ls, rk);
    } else if (tree[ls].siz + tree[p].cnt < rk) {
        return fnd(rs, rk - tree[ls].siz - tree[p].cnt);
    } else {
        return tree[p].val;
    }
}

// 查询某个数的前驱
inline int pre(int p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return -inf;
    if (tree[p].val >= val) {
        return pre(ls, val);
    } else {
        return max(tree[p].val, pre(rs, val));
    }
}

// 查询某个数的后继
inline int nxt(int p, int val) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (!p) return inf;
    if (tree[p].val <= val) {
        return nxt(rs, val);
    } else {
        return min(tree[p].val, nxt(ls, val));
    }
}

void print(int p) {
    auto &ls = tree[p].ch[0], &rs = tree[p].ch[1];
    if (ls) print(ls);
    cout << tree[p].val << ' ';
    if (rs) print(rs);
}

void solve() {
    int n, q;
    read(n, q);
    int root = 0;
    for (int i = 0; i < n; i++) {
        read(a[i]);
    }
    sort(a, a + n);
    root = build(a, n);
    int last = 0, ans = 0;
    for (int i = 1; i <= q; i++) {
        int op, x;
        read(op, x);
        x ^= last;
        if (op == 1) {
            ins(root, x);
        } else if (op == 2) {
            del(root, x);
        } else if (op == 3) {
            last = rnk(root, x);
            ans ^= last;
        } else if (op == 4) {
            last = fnd(root, x);
            ans ^= last;
        } else if (op == 5) {
            last = pre(root, x);
            ans ^= last;
        } else if (op == 6) {
            last = nxt(root, x);
            ans ^= last;
        }
    }
    write(ans, '\n');
}
posted @ 2024-12-22 14:54  grape_king  阅读(21)  评论(0)    收藏  举报