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\n", Rank(root, x));break;
            case 4: printf("%d\n", Kth(root, x));break;
            case 5: printf("%d\n", Kth(root, Rank(root, x) - 1));break;
            case 6: printf("%d\n", Kth(root, Rank(root, x + 1)));break;
        }
    }
    return 0;
}

 

posted on 2016-11-17 15:03  yohaha  阅读(130)  评论(0编辑  收藏  举报

导航