BZOJ3224 Tyvj 1728 普通平衡树 (替罪羊树)

本文介绍了替罪羊树(scapegoat tree)的数据结构及其应用。替罪羊树是一种自平衡二叉搜索树,通过在删除操作中进行局部重构来维持平衡。文中详细解释了替罪羊树的插入、删除及查找操作,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

思路:
                   学习一下替罪羊树。 替罪羊树就是确定一个 α α 因子,插入和常规平衡树插入无太大区别, 删除的时候节点还在, 只是做个标记已经删除过,然后查找和普通平衡树也没太大区别, 构建的时候当当前节点 x x 的子树大小 * α 某一个孩子子树的大小的时候, 暴力重建 x x 子树就是了。α的值一般取 0.7 0.7

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 3e5 + 10;
const double alpha = 0.7;
using namespace std;

int stk[maxn], top, n, m, root;
int ls[maxn], rs[maxn], siz[maxn], travel[maxn];
int cnt[maxn], v[maxn], t1, goat;
bool exist[maxn];

int get_rank(int x) {
    int now = root, ans = 1;
    while(now) {
        if(v[now] >= x) now = ls[now];
        else {
            ans += siz[ls[now]] + exist[now];
            now = rs[now];
        }
    }
    return ans;
}

void dfs(int rt) {
    if(!rt) return ;
    dfs(ls[rt]);
    if(exist[rt]) travel[++t1] = rt;
    else stk[++top] = rt;
    dfs(rs[rt]);
}

void build(int &rt, int l, int r) {
    int mid = (l + r) >> 1;
    rt = travel[mid];
    if(l == r) {
        siz[rt] = cnt[rt] = 1;
        ls[rt] = rs[rt] = 0;
        return ;
    }
    if(l < mid) build(ls[rt], l, mid - 1);
    else ls[rt] = 0;
    if(mid < r) build(rs[rt], mid + 1, r);
    else rs[rt] = 0;
    siz[rt] = siz[ls[rt]] + siz[rs[rt]] + 1;
    cnt[rt] = cnt[ls[rt]] + cnt[rs[rt]] + 1;
}

void rebuild(int &rt) {
    t1 = 0; dfs(rt);
    if(t1) build(rt, 1, t1);
    else rt = 0;
}

void __insert(int &rt, int x) {
    if(rt == 0) {
        rt = stk[top--]; v[rt] = x;
        siz[rt] = cnt[rt] = exist[rt] = 1;
        ls[rt] = rs[rt] = 0;
        return ;
    } else {
        siz[rt]++; cnt[rt]++;
        if(x >= v[rt]) __insert(rs[rt], x);
        else __insert(ls[rt], x);
        if(siz[rt] * alpha < max(siz[ls[rt]], siz[rs[rt]])) rebuild(rt);
    }
}

int get_kth(int x) {
    int now = root;
    while(now) {
        if(exist[now] && siz[ls[now]] + 1 == x) return v[now];
        if(x <= siz[ls[now]]) now = ls[now];
        else {
            x -= exist[now] + siz[ls[now]];
            now = rs[now];
        }
    }
}

void __delete(int &rt, int rk) {
    if(exist[rt] && rk == siz[ls[rt]] + 1) {
        exist[rt] = false;
        siz[rt]--; return ;
    }
    if(!rt) return ;
    siz[rt]--;
    if(rk <= siz[ls[rt]] + exist[rt]) __delete(ls[rt], rk);
    else __delete(rs[rt], rk - exist[rt] - siz[ls[rt]]);
}


int main() {
    scanf("%d", &n); root = 0;
    for(int i = maxn - 2; i >= 1; i--) stk[++top] = i;
    for(int i = 1; i <= n; i++) {
        int opt, x;
        scanf("%d %d", &opt, &x);
        if(opt == 1) __insert(root, x);
        if(opt == 2) __delete(root, get_rank(x));
        if(opt == 3) printf("%d\n", get_rank(x));
        if(opt == 4) printf("%d\n", get_kth(x));
        if(opt == 5) printf("%d\n", get_kth(get_rank(x) - 1));
        if(opt == 6) printf("%d\n", get_kth(get_rank(x + 1)));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值