bzoj 3224 普通平衡树 (Splay)

题目

思路:Splay模板题

代码:

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000000
//f[i]表示i的父结点,ch[i][0]表示i的左儿子,ch[i][1]表示i的右儿子,
//key[i]表示i的关键字(即结点i代表的那个数字),cnt[i]表示i结点的关键字出现的次数(相当于权值),
//size[i]表示包括i的这个子树的大小;sz为整棵树的大小,root为整棵树的根。
int ch[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],key[MAXN];
int sz,root;
//将当前点的各项值都清0(用于删除之后)
void clear(int x)
{
    ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
}
//判断当前点是它父结点的左儿子还是右儿子
bool get(int x)
{
    return ch[f[x]][1]==x;
}
//更新当前点的size值(用于发生修改之后)
void update(int x)
{
    if(x)
    {
        size[x]=cnt[x];
        if(ch[x][0])size[x]+=size[ch[x][0]];
        if(ch[x][1])size[x]+=size[ch[x][1]];
    }
}

void rotate(int x)
{
    int old=f[x],oldf=f[old],whichx=get(x);
    ch[old][whichx]=ch[x][whichx^1];
    f[ch[old][whichx]]=old;
    ch[x][whichx^1]=old;
    f[old]=x;
    f[x]=oldf;
    if(oldf)
        ch[oldf][ch[oldf][1]==old]=x;
    update(old);
    update(x);
}
void splay(int x)
{
    for(int fa;fa=f[x];rotate(x))
        if(f[fa])
        rotate((get(x)==get(fa))?fa:x);
    root=x;
}
void insert(int v)
{
    if(root==0)
    {
        sz++;
        ch[sz][0]=ch[sz][1]=f[sz]=0;
        key[sz]=v;
        cnt[sz]=1;
        size[sz]=1;
        root=sz;
        return;
    }
    int now=root,fa=0;
    while(1)
    {
        if(key[now]==v)
        {
            cnt[now]++;
            update(now);
            update(fa);
            splay(now);
            break;
        }
        fa=now;
        now=ch[now][key[now]<v];
        if(now==0)
        {
            sz++;
            ch[sz][0]=ch[sz][1]=0;
            key[sz]=v;
            size[sz]=cnt[sz]=1;
            ch[fa][key[fa]<v]=sz;
            f[sz]=fa;
            update(fa);
            splay(sz);
            break;
        }
    }
}
//查询x的排名
int find(int v)
{
    int ans=0,now=root;
    while(1)
    {
        if(v<key[now])
        {
            now=ch[now][0];
        }
        else
        {
            ans+=(ch[now][0]?size[ch[now][0]]:0);
            if(v==key[now])
            {
                splay(now);return ans+1;
            }
            ans+=cnt[now];
            now=ch[now][1];
        }
    }
}
//找到排名为x的点
int findx(int x)
{
    int now=root;
    while(1)
    {
        if(ch[now][0]&&x<=size[ch[now][0]])
        {
            now=ch[now][0];
        }
        else
        {
            int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
            if(x<=temp)
                return key[now];
            x-=temp;
            now=ch[now][1];
        }
    }
}
int pre()
{
    int now=ch[root][0];
    while(ch[now][1])
    {
        now=ch[now][1];
    }
    return now;
}
int next()
{
    int now=ch[root][1];
    while(ch[now][0])now=ch[now][0];
    return now;
}
void del(int x)
{
    int whatever=find(x);
    if(cnt[root]>1){cnt[root]--;update(root);return;}
    if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}
    if(!ch[root][0])
    {
        int oldroot=root;
        root=ch[root][1];
        f[root]=0;
        clear(oldroot);
        return;
    }
    else if(!ch[root][1])
    {
        int oldroot=root;
        root=ch[root][0];
        f[root]=0;
        clear(oldroot);
        return ;
    }
    int leftc=pre(),oldroot=root;
    splay(leftc);
    f[ch[oldroot][1]]=root;
    ch[root][1]=ch[oldroot][1];
    clear(oldroot);
    update(root);
    return;
}
int main()
{
   int n,opt,x;
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d%d",&opt,&x);
        if(opt==1)
        {
            insert(x);
        }
        else if(opt==2)
        {
            del(x);
        }
        else if(opt==3)
        {
            printf("%d\n",find(x));
        }
        else if(opt==4)
        {
            printf("%d\n",findx(x));
        }
        else if(opt==5)
        {
            insert(x);
            printf("%d\n",key[pre()]);
            del(x);
        }
        else
        {
            insert(x);
            printf("%d\n",key[next()]);
            del(x);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/imzxww/article/details/81251833