BZOJ 3224 普通平衡树

普通平衡树

【问题描述】

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

【输入格式】

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

【输出格式】

对于操作3,4,5,6每行输出一个数,表示对应答案

【样例输入】

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

【样例输出】

106465
84185
492737

【数据范围】

1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]

题解:

裸平衡

删除操作稍微注意一下就好了

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e6;
int n;
int sma, big;
int num, root;
int lc[maxn], rc[maxn], fat[maxn];
int si[maxn], cnt[maxn], val[maxn];
inline void Print(int k)
{
    if(!k) return;
    Print(lc[k]);
    printf("%d ", val[k]);
    Print(rc[k]);
}
inline void Printtree(int k)
{
    if(!k) return;
    printf("k=%d lc=%d rc=%d fat=%d val=%d \n", k, lc[k], rc[k], fat[k], val[k]);
    Printtree(lc[k]);
    Printtree(rc[k]);
}
inline void Scan(int &x)
{
    char c;
    bool o = false;
    while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
    x = c - '0';
    while(isdigit(c = getchar())) x = x * 10 + c - '0';
    if(o) x = -x;
}
inline void Update(int x)
{
    si[x] = si[lc[x]] + si[rc[x]] + cnt[x];
}
inline void Turn(int x)
{
    int y = fat[x], z = fat[y];
    int w = (lc[y] != x) ? lc[x] : rc[x];
    fat[x] = z;
    fat[y] = x;
    if(w) fat[w] = y;
    if(z)
    {
        if(lc[z] == y) lc[z] = x;
        else rc[z] = x;
    }
    if(lc[y] == x) rc[x] = y, lc[y] = w;
    else lc[x] = y, rc[y] = w;
    Update(y);
}
inline void Splay(int x, int anc)
{
    while(fat[x] != anc)
    {
        if(fat[fat[x]] != anc)
            if((lc[fat[x]] == x) == (lc[fat[fat[x]]] == fat[x])) Turn(fat[x]);
            else Turn(x);
        Turn(x);
    }
    if(!anc) root = x;
    Update(x);
}
inline int Insert(int x)
{
    int f, d = 2, k = root;
    while(true)
    {
        if(!k)
        {
            si[++num] = 1;
            cnt[num] = 1;
            fat[num] = f;
            val[num] = x;
            if(d == 0) lc[f] = num;
            if(d == 1) rc[f] = num;
            Splay(num, 0);
            return num;
        }
        ++si[k];
        if(x == val[k])
        {
            ++cnt[k];
            Splay(k, 0);
            return k;
        }
        f = k;
        if(x < val[k]) d = 0, k = lc[k];
        else d = 1, k = rc[k];
    }
}
inline int Findnum(int x)
{
    int k = root;
    while(true)
    {
        if(x == val[k]) return k;
        if(x < val[k]) k = lc[k];
        else k = rc[k];
    }
}
inline void Clear(int x)
{
    lc[x] = rc[x] = fat[x] = 0;
}
inline void Del(int x)
{
    int k = Findnum(x);
    --cnt[k];
    Splay(k, 0);
    if(cnt[k]) return;
    int s = lc[k];
    while(rc[s]) s = rc[s];
    if(s)
    {
        Splay(s, k);
        rc[s] = rc[k];
        fat[rc[k]] = s;
        root = s;
        fat[s] = 0;
    }
    else
    {
        root = rc[k];
        fat[rc[k]] = 0;
    }
    Clear(k);
}
inline int Findval(int x)
{
    int k = root, sum;
    while(true)
    {
        sum = si[lc[k]] + cnt[k];
        if(si[lc[k]] < x && x <= sum) return val[k];
        if(x > sum) k = rc[k], x -= sum;
        else k = lc[k];
    }
}
inline int Findrank(int x)
{
    int k = root, sum, ans = 0;
    while(true)
    {
        sum = si[lc[k]] + cnt[k];
        if(x == val[k]) return ans + si[lc[k]] + 1;
        if(x < val[k]) k = lc[k];
        else k = rc[k], ans += sum;
    }
}
inline int Pre(int x)
{
    int k = root, ans;
    while(k)
    {
        if(x > val[k]) ans = val[k], k = rc[k];
        else k = lc[k];
    }
    return ans;
}
inline int Next(int x)
{
    int k = root, ans;
    while(k)
    {
        if(x < val[k]) ans = val[k], k = lc[k];
        else k = rc[k];
    }
    return ans;
}
int main()
{
    Scan(n);
    int opt, x;
    while(n--)
    {
        Scan(opt), Scan(x);
        switch(opt)
        {
            case 1:
            {
                int k = Insert(x);
                break;
            }
            case 2:
            {
                Del(x);
                break;
            }
            case 3:
            {
                printf("%d\n", Findrank(x));
                break;
            }
            case 4:
            {
                printf("%d\n", Findval(x));
                break;
            }
            case 5:
            {
                printf("%d\n", Pre(x));
                break;
            }
            case 6:
            {
                printf("%d\n", Next(x));
                break;
            }
        }
    }
}
posted @ 2017-05-24 15:37  草根柴鸡  阅读(181)  评论(0编辑  收藏  举报