求助替罪羊树

P6136 【模板】普通平衡树(数据加强版)

李嘉豪 @ 2020-12-19 21:19:04

今天晚上想学习一下替罪羊树,顺利的过掉了普通版的数据,跑得也比之前写的其他平衡树快一些,但是在加强版却只有50分,我将alpha分别改为0.8,0.85,0.9分别得到了60分,80分和90分但是按道理系数这么大是不太对劲的。另外我突发奇想在求排名,kth等操作之中都判断一下平衡,但是直接就成了MLE,求哪位巨佬帮忙检查一下板子,代码里面写上了注释,感激不尽。

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 5e6 + 10;
const double alpha = 0.75;
#define rint register int
int read() {
    int s = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        s = (s << 1) + (s << 3) + (ch ^ 48);
        ch = getchar();
    }
    return s * f;
}
struct Tree {
    int ch[2], val, siz, liv; //ch为两个儿子,val为权值,siz为节点个数(未知是否存在),liv为存在的节点个数
    bool exist;
} tree[N];
#define ls(t) tree[t].ch[0] //分别表示左右儿子和中点
#define rs(t) tree[t].ch[1]
#define mid ((l + r) >> 1)
int root;
int Pool[N], tail, tot, cnt[N], top; //Pool是内存池用tail做指针,cnt数组暂存被重构的节点用top做指针
int New(rint val) { //新建一个节点
    rint pos = tail ? Pool[tail--] : ++tot;
    tree[pos].ch[0] = tree[pos].ch[1] = 0;
    tree[pos].val = val;
    tree[pos].siz = tree[pos].liv = tree[pos].exist = 1;
    return pos;
}
bool isbad(rint t) { //判断是否需要重构
    rint now = std::max(tree[ls(t)].siz, tree[rs(t)].siz);
    if((double)tree[t].siz * alpha <= now) return true;
    return false;
}
void dfs(int t) { //中序遍历,取出重构的序列
    if(ls(t)) dfs(ls(t));
    if(tree[t].exist) cnt[++top] = t;
    else Pool[++tail] = t;
    if(rs(t)) dfs(rs(t));
}
void pushup(int t) { //向上修改
    tree[t].siz = tree[ls(t)].siz + tree[rs(t)].siz + 1;
    tree[t].liv = tree[ls(t)].liv + tree[rs(t)].liv + tree[t].exist;
}
void build(rint &t, rint l, rint r) { //重构树
    if(l > r) return t = 0, void();
    t = cnt[mid];
    build(ls(t), l, mid - 1);
    build(rs(t), mid + 1, r);
    pushup(t);
}
void rebuild(rint &t) { //重构一条龙
    top = 0;
    dfs(t);
    build(t, 1, top);
}
void Insert(rint &t, rint val) { //插入节点
    if(!t) { //到达叶子
        t = New(val);
        return;
    }
    tree[t].siz++; tree[t].liv++; 
    if(isbad(t)) rebuild(t); //判断重构
    if(val <= tree[t].val) Insert(ls(t), val);
    else Insert(rs(t), val);
    pushup(t);
}
void del_kth(rint t, rint rnk) { //删除第k个节点
    rint x = tree[ls(t)].liv;
    if(tree[t].exist && x + 1 == rnk) {
        tree[t].exist = 0; 
        tree[t].liv--;
        return;
    }
    tree[t].liv--;
    if(x >= rnk) del_kth(ls(t), rnk);
    else del_kth(rs(t), rnk - x - tree[t].exist);
}
int kth(rint t, rint k) { //求出第k个节点
    rint x = tree[ls(t)].liv;
    if(tree[t].exist && x + 1 == k) {
        return tree[t].val;
    }
    if(x >= k) return kth(ls(t), k);
    else return kth(rs(t), k - x - tree[t].exist);
}
int rank(rint t, rint val) { //求排名
    if(!t) return 0;
    int x = tree[ls(t)].liv + tree[t].exist;
    if(tree[t].val < val) return rank(rs(t), val) + x;
    else return rank(ls(t), val);
}
void del(rint val) { //删除节点
    rint rnk = rank(root, val) + 1;
    del_kth(root, rnk);
}
int pre(rint val) { //求前趋
    rint rnk = rank(root, val);
    return kth(root, rnk);
}
int nxt(rint val) { //求后继
    rint rnk = rank(root, val + 1) + 1;
    return kth(root, rnk);
}
int main() {
    rint n = read(), m = read(), res = 0, ans = 0;
    for(rint i = 1; i <= n; ++i) {
        rint w = read();
        Insert(root, w);
    }
    for(rint i = 1; i <= m; ++i) {
        rint op = read(), x = read();
        x ^= res;
        if(op == 1) Insert(root, x);
        else if(op == 2) del(x);
        else if(op == 3) res = rank(root, x) + 1;
        else if(op == 4) res = kth(root, x);
        else if(op == 5) res = pre(x);
        else if(op == 6) res = nxt(x);
        if(op != 1 && op != 2) ans ^= res;
    }
    printf("%d\n", ans);
    return 0;
}

by UltiMadow @ 2020-12-19 21:39:55

@李嘉豪 平衡常数 0.7-0.8 范围内试一试吧(

没必要所有操作都判平衡吧


by UltiMadow @ 2020-12-19 21:40:52

我测下来0.75最优(


by suxxsfe @ 2020-12-19 21:49:03

在insert时应该不是没找到一个坏节点就重构,因为在那之上它的某个祖先也会是坏的,所以应该在insert的路径上记录一个最考上坏节点的指针,然后只重构一次
但这并不会对时间造成太大影响,TLE可能是alpha太大了

并不是所有操作都要判平衡


by suxxsfe @ 2020-12-19 21:49:29

在insert时应该不是找到一个坏节点就重构


by hzoi_liuchang @ 2020-12-20 06:58:07

%%%%


|