• bzoj 3224: Tyvj 1728 普通平衡树 替罪羊树


    题目链接

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    这题用替罪羊树过的。

    替罪羊树, 其实就是一种很暴力的方法。 如果一个节点的左子树节点个数大于它节点个数*alpha或者右子树节点个数大于节点个数*alpha。 那么就将这个节点及它的子树重构。

    重构非常暴力, 就是把它变成一个序列, 然后不停的找中点。 相当于将之前的不平衡的二叉树变成了一个完全二叉树。

    在删除时, 并不是直接删除, 而是将这个节点打个标记。

    代码中, sz是有效节点的个数, 而cover是总结点的个数。 在删除的时候, 如果根节点的sz < alpha*cover。 那么就将整棵树重构。

    #include <bits/stdc++.h>
    
    using namespace std;
    #define MAXN 100010
    const double alpha = 0.75;
    struct node
    {
        int sz, cover, val;
        bool exist;
        node* ch[2];
        node()
        {
            ch[0] = ch[1] = NULL;
            exist = false;
            sz = cover = 0;
        }
        node(int val):val(val)
        {
            sz = cover = 1;
            exist = true;
            ch[0] = ch[1] = NULL;
        }
        void pushUp(node* tmp)
        {
            sz += tmp->sz;
            cover += tmp->cover;
        }
        bool isBad()
        {
            int tmpL = ch[0]?ch[0]->cover:0;
            int tmpR = ch[1]?ch[1]->cover:0;
            if(tmpL > cover * alpha + 5 ||
               tmpR > cover * alpha + 5)
                return true;
            return false;
        }
    };
    node* root = NULL;
    void add(node*& p, int val, node** flag)
    {
        if(p == NULL) {
            p = new node(val);
            return ;
        }
        p->sz++;
        p->cover++;
        add(p->ch[val >= p->val], val, flag);
        if(p->isBad()) {
            flag = &p;
        }
    }
    void Erase(node* p, int k)
    {
        int x = p->ch[0]?p->ch[0]->sz:0;
        int tmp = x + (int)(p->exist);
        p->sz--;
        if(p->exist && tmp == k) {
            p->exist = false;
            return ;
        }
        if(k <= tmp) {
            Erase(p->ch[0], k);
        } else {
            Erase(p->ch[1], k - tmp);
        }
    }
    void traval(node*& p, vector<node*>& v)
    {
        if(p == NULL)
            return ;
        traval(p->ch[0], v);
        if(p->exist) {
            v.push_back(p);
        }
        traval(p->ch[1], v);
    }
    void divide(node*& p, vector<node*>& v, int l, int r)
    {
        if(l > r)
            return ;
        if(p == NULL)
            p = new node();
        int mid = l + r >> 1;
        p = v[mid];
        divide(p->ch[0], v, l, mid - 1);
        divide(p->ch[1], v, mid + 1, r);
        if(p->ch[0])
            p->pushUp(p->ch[0]);
        if(p->ch[1])
            p->pushUp(p->ch[1]);
        if(p->exist)
            p->sz++;
        p->cover++;
    }
    void rebuild(node*& p)
    {
        vector <node*> v;
        traval(p, v);
        divide(p, v, 0, v.size()-1);
    }
    int Rank(node*& p, int x)
    {
        if(p == NULL)
            return 1;
        int ret = 0;
        if(p->val >= x) {
            ret = Rank(p->ch[0], x);
        } else {
            int tmp = (p->ch[0])?p->ch[0]->sz:0;
            ret = tmp + (int)p->exist;
            ret += Rank(p->ch[1], x);
        }
        return ret;
    }
    int Kth(node*& p, int k)
    {
        if(p == NULL)
            return 1;
        int tmp = (p->ch[0])?p->ch[0]->sz:0;
        if(p->exist && tmp + 1 == k)
            return p->val;
        if(tmp >= k) {
            return Kth(p->ch[0], k);
        } else {
            return Kth(p->ch[1], k - tmp - p->exist);
        }
    }
    void Insert(int val)
    {
        node** flag = NULL;
        add(root, val, flag);
        if(flag != NULL) {
            rebuild(*flag);
        }
    }
    void Erase(int k)
    {
        Erase(root, k);
        if((double)root->sz < (double)(alpha*root->cover))
            rebuild(root);
    }
    int main()
    {
        int n, sign, x;
        cin>>n;
        while(n--) {
            scanf("%d%d", &sign, &x);
            switch(sign) {
                case 1: Insert(x);break;
                case 2: Erase(root, Rank(root, x));break;
                case 3: printf("%d
    ", Rank(root, x));break;
                case 4: printf("%d
    ", Kth(root, x));break;
                case 5: printf("%d
    ", Kth(root, Rank(root, x) - 1));break;
                case 6: printf("%d
    ", Kth(root, Rank(root, x + 1)));break;
            }
        }
        return 0;
    }
  • 相关阅读:
    如何阅读一篇论文
    FT232R驱动问题
    无线传感网-定位技术1
    无线传感网中常见路由协议2
    课程总结
    十四周总结以及实验报告
    第十三周总结
    第十二周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
  • 原文地址:https://www.cnblogs.com/yohaha/p/6073345.html
Copyright © 2020-2023  润新知