其他分享
首页 > 其他分享> > 替罪羊树

替罪羊树

作者:互联网

替罪羊树

一.是什么?

这个名字我也不知道是个啥,但是它是一种平衡树,别的平衡树都是通过旋转来维护平衡,而我们的替罪羊树就不一样,它就是一个

暴躁老哥!!!

不多废话,我们来康一康它是如何实现的.

二.为什么?

让我们来先看一下它最暴力的操作

显然,这棵树不讲武德,肯定是要排扁重构的,我们把它变成一条链

然后把它从中间拎起来,得到

这样,这一棵树就被重构好了.

我们该如何判断要不要重构呢?,我们要引入一个平衡因子\(\alpha=(0.5,1)\)但是我经常用\(\alpha=0.8\)好像在洛谷上最快

如果一个树它的子数大小$ \leq siz_{cur} \times \alpha$,那么这棵树还懂一点传统功夫,不用收到制裁,否则就要吧这个子树暴力重构一下

三.怎么做?

1.定义变量

struct Scapegoat
{
    int Son[2], Exist, Val, Size, Fac;
} node[N + 5];

2.判断是否需要拍瘪

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);
}

3.新建一个节点

inline void Build(int x)
{
    node[x].Son[0] = node[x].Son[1] = 0, node[x].Size = node[x].Fac = 1;
}

4.插入一个节点

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);
}

5.重构!!!!!!

inline void Traversal(int x)
{
    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;
    }
}

6.其它操作

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);
}

四.完结撒花

要完整代码的康过来

标签:node,int,替罪羊,Son,inline,Fac,rk
来源: https://www.cnblogs.com/zhangwenxuan/p/14063876.html