• 替罪羊树学习总结


    替罪羊树学习总结ScapeGoat Tree

    暴力即优雅——替罪羊树

    学习链接
    各种不同平衡树的算法其本质上的区别在于通过不同的方式维护树的形态,保证每次操作的时间复杂度为(log)

    替罪羊树的核心思想是暴力重构,设定一个参数(ain[0.5,1))其实取到0.5会T飞,对于每颗子树满足(son1/son2.size<a*tree.size)

    bool bad(int k)
    {
        int k1=t[k].son[0],k2=t[k].son[1];
        return (double)max(t[k1].s,t[k2].s)>=(double)t[k].s*alpha;
    }
    

    变量解释

    double alpha=0.75;//平衡因子
    int s[100010];//重构数组
    struct node{
        int son[2],v,die,s;//两个儿子,权值,是否被删除,子树大小
    }t[100010];
    

    重构

    void dfs(int k)
    {
        if(!k) return;
        dfs(t[k].son[0]);if(!t[k].die)s[++top]=k;dfs(t[k].son[1]);
    }
    void build(int &k,int l,int r)
    {
        if(l>r)return;int mid=(l+r)/2;k=s[mid];
        if(l==r)
        {
            t[k].s=1;t[k].son[0]=t[k].son[1]=t[k].die=0;return;
        }
        if(l<mid) build(t[k].son[0],l,mid-1);else t[k].son[0]=0;
        if(r>mid) build(t[k].son[1],mid+1,r);else t[k].son[1]=0;
        t[k].s=t[t[k].son[0]].s+t[t[k].son[1]].s+1;return;
    }
    void rebuild(int &k)
    {
        top=0;dfs(k);if(top)build(k,1,top);
    }
    

    插入操作

    插入操作与普通BST基本无区别,但是每次插入完需要判断是否需要重构,找到深度最浅的需要重构的点进行重构。

    void insert(int &k,int v)
    {
        if(!k)
        {
            k=++cnt;t[k].v=v;t[k].s=1;return;
        }
        if(v<=t[k].v) insert(t[k].son[0],v);
        else insert(t[k].son[1],v);
        int k1=t[k].son[0],k2=t[k].son[1];
        t[k].s=t[k1].s+t[k2].s+exist(k);
        if(!bad(k))
        {
            if(need)
            {
                if(need==t[k].son[0]) rebuild(t[k].son[0]);
                else rebuild(t[k].son[1]);
            }
            need=0;
        }
        else need=k;
    }
    

    删除操作

    删除操作并不需要真正删除节点,只需要给这个节点打上标记,在之后处理的时候忽略掉就可以啦

    void delet(int k,int v)
    {
        if(!k) return;
        int k1=t[k].son[0],k2=t[k].son[1];
        if(!t[k].die&&t[k1].s+1==v){t[k].die=1;t[k].s--;return;}
        if(t[k1].s>=v) delet(k1,v);
        else delet(k2,v-t[k1].s-exist(k));
        t[k].s=t[k1].s+t[k2].s+exist(k);
        if(!bad(k))
        {
            if(need)
            {
                if(need==t[k].son[0]) rebuild(t[k].son[0]);
                else rebuild(t[k].son[1]);
            }
            need=0;
        }
        else need=k;
    }
    

    查询操作

    查询操作与普通BST操作没有区别。

    例题:

    [模板]普通平衡树
    [NOI2004]郁闷的出纳员

  • 相关阅读:
    Redis的四种模式,单机、主从、哨兵、集群
    .NET 跨域问题
    C# 利用正则表达式获取富文本框中所有图片路劲
    ActiveMQ入门实例(.NET)
    ActiveMQ的使用以及应用场景
    关于消息队列的使用方法(RocketMQ)
    Redis系列 需要注意事项
    .NET:在线悲观锁、在线乐观锁、离线悲观锁、离线乐观锁代码示例
    C# 简单介绍Redis使用
    API Get跟Post 的区别?
  • 原文地址:https://www.cnblogs.com/lsgjcya/p/9349204.html
Copyright © 2020-2023  润新知