洛谷P3369 【模板】普通平衡树

本文介绍了一种数据结构——替罪羊树,并提供了详细的代码实现。替罪羊树是一种自平衡二叉搜索树,用于高效地进行元素查找、插入和删除操作。文中详细解释了树的初始化、插入、重构等关键步骤。

替罪羊树:

#include <bits/stdc++.h>
#define N 100000
using namespace std;
int n, st, rt, cnt, tot, cur[N + 5],
    Void[N + 5];            // rt就是根节点,st就是当前节点
const double alpha = 0.75;  //关联因子
struct Scapegoat {
    int Son[2], Exist, Val, Size, Fac;  // Son里面是0是左子树,1是右子树
} node[N + 5];
inline char tc() {  //被快读调用的函数
    static char ff[100000], *A = ff, *B = ff;
    return A == B && (B = (A = ff) + fread(ff, 1, 100000, stdin), A == B)
               ? EOF
               : *A++;
}
inline void read(int& x) {  //快读
    x = 0;
    int f = 1;
    char ch;
    while (!isdigit(ch = tc()))
        if (ch == '-')
            f = -1;
    while (x = (x << 3) + (x << 1) + ch - '0', isdigit(ch = tc()))
        ;
    x *= f;
}
inline void write(int x) {  //快写
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
inline void Init() {  //初始化编号
    tot = 0;
    for (register int i = N - 1; i; --i)
        Void[++tot] = i;
}
inline bool balance(int x) {  //检查这棵树是否平衡
    return (double)node[x].Fac * alpha >
           (double)max(node[node[x].Son[0]].Fac, node[node[x].Son[1]].Fac);
}
inline void Build(int x) {  //给新节点赋值
    node[x].Son[0] = node[x].Son[1] = 0, node[x].Size = node[x].Fac = 1;
}
inline void Insert(int& x, int val) {  //插入新结点
    if (!x) {
        x = Void[tot--], node[x].Val = val, node[x].Exist = 1, Build(x);
        return;
    }
    ++node[x].Size, ++node[x].Fac;
    if (val <= node[x].Val)
        Insert(node[x].Son[0], val);
    else
        Insert(node[x].Son[1], val);
}
inline void PushUp(int x) {  //重构的时候给每个新节点赋值
    node[x].Size = node[node[x].Son[0]].Size + node[node[x].Son[1]].Size + 1,
    node[x].Fac = node[node[x].Son[0]].Fac + node[node[x].Son[1]].Fac + 1;
}
inline void Traversal(int x) {  //把这棵子树都给拍平了(放在同一个cur数组里面)
    if (!x)
        return;
    Traversal(node[x].Son[0]);
    if (node[x].Exist)
        cur[++cnt] = x;
    else
        Void[++tot] = x;
    Traversal(node[x].Son[1]);
}
inline void SetUp(int l, int r, int& x) {  //重构里面的提出根节点
    int mid = l + r >> 1;
    x = cur[mid];
    if (l == r) {
        Build(x);
        return;
    }
    if (l < mid)
        SetUp(l, mid - 1, node[x].Son[0]);
    else
        node[x].Son[0] = 0;
    SetUp(mid + 1, r, node[x].Son[1]), PushUp(x);
}
inline void ReBuild(int& x) {  //虚假的重构函数
    cnt = 0, Traversal(x);
    if (cnt)
        SetUp(1, cnt, x);
    else
        x = 0;
}
inline void check(int x, int val) {  //检查插入节点时候是否需要重构
    int s = val <= node[x].Val ? 0 : 1;
    while (node[x].Son[s]) {
        if (!balance(node[x].Son[s])) {
            ReBuild(node[x].Son[s]);
            return;
        }
        x = node[x].Son[s], s = val <= node[x].Val ? 0 : 1;
    }
}
inline int get_rank(int v) {  //由数值查询排名
    int x = rt, rk = 1;
    while (x) {
        if (node[x].Val >= v)
            x = node[x].Son[0];
        else
            rk += node[node[x].Son[0]].Fac + node[x].Exist, x = node[x].Son[1];
    }
    return rk;
}
inline int get_val(int rk) {  //由排名查询数值
    int x = rt;
    while (x) {
        if (node[x].Exist && node[node[x].Son[0]].Fac + 1 == rk)
            return node[x].Val;
        else if (node[node[x].Son[0]].Fac >= rk)
            x = node[x].Son[0];
        else
            rk -= node[x].Exist + node[node[x].Son[0]].Fac, x = node[x].Son[1];
    }
}
inline void Delete(int& x, int rk) {  //真正的删除
    if (node[x].Exist && !((node[node[x].Son[0]].Fac + 1) ^ rk)) {
        node[x].Exist = 0, --node[x].Fac;
        return;
    }
    --node[x].Fac;
    if (node[node[x].Son[0]].Fac + node[x].Exist >= rk)
        Delete(node[x].Son[0], rk);
    else
        Delete(node[x].Son[1], rk - node[x].Exist - node[node[x].Son[0]].Fac);
}
inline void del(int v) {  //虚假的删除+重构
    Delete(rt, get_rank(v));
    if ((double)node[rt].Size * alpha > (double)node[rt].Fac)
        ReBuild(rt);
}
int main() {
    for (read(n), Init(); n; --n) {
        int op, x;
        read(op), read(x);
        switch (op) {
            case 1:
                st = rt, Insert(rt, x), check(st, x);
                break;
            case 2:
                del(x);
                break;
            case 3:
                write(get_rank(x)), putchar('\n');
                break;
            case 4:
                write(get_val(x)), putchar('\n');
                break;
            case 5:
                write(get_val(get_rank(x) - 1)), putchar('\n');
                break;
            case 6:
                write(get_val(get_rank(x + 1))), putchar('\n');
                break;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值