【BZOJ3224】 Tyvj 1728 普通平衡树

7 篇文章 0 订阅

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

106465
84185
492737

HINT

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

Solution

请参考题目名:普通平衡树
那就打个平衡树呗
我打的splay
六个操作分别维护即可,裸的

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1010000
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,t[N][2],g[N],size[N],fa[N],tot,root,siz[N];
int lr(int x){return x==t[fa[x]][1];}
void update(int x){size[x]=size[t[x][0]]+size[t[x][1]]+siz[x];}
void rotate(int x)
{
    int y=fa[x],k=lr(x);
    t[y][k]=t[x][1-k];
    if(t[x][1-k]) fa[t[x][1-k]]=y;
    fa[x]=fa[y];
    if(fa[y]) t[fa[y]][lr(y)]=x;
    t[x][1-k]=y;fa[y]=x;
    update(y);update(x);
}
void splay(int x,int y)
{
    if(x==y) return;
    while(fa[x]!=y)
    {
        if(fa[fa[x]]!=y)
            if(lr(x)==lr(fa[x])) rotate(fa[x]);
            else rotate(x);
        rotate(x);
    }
    if(y==0) root=x;
}
int kth(int x)
{
    int y=root;
    while(g[y]!=x)
    {
        if(x<g[y]) y=t[y][0];else y=t[y][1];
    }
    return y;
}
int xth(int x,int y)
{
    if(size[t[y][0]]+siz[y]>=x&&size[t[y][0]]<x) return y;
    if(x<=size[t[y][0]]) return xth(x,t[y][0]);
    else return xth(x-size[t[y][0]]-siz[y],t[y][1]);
}
int kthsmall(int x,int y)
{
    if(y==0) return -2147483647;
    if(x>g[y]) return max(g[y],kthsmall(x,t[y][1]));
    else return kthsmall(x,t[y][0]);
}
int kthbig(int x,int y)
{
    if(y==0) return 2147483647;
    if(x<g[y]) return min(g[y],kthbig(x,t[y][0]));
    else return kthbig(x,t[y][1]);
}
void put(int y,int z,int x)
{
    splay(y,0);splay(z,y);
    if(t[z][0]!=0) siz[t[z][0]]++;
    else
    {
        g[++tot]=x;t[z][0]=tot;fa[tot]=z;
        size[tot]=siz[tot]=1;
    }
    update(t[z][0]);update(z);update(y);
}
int main()
{
    scanf("%d",&n);
    tot=2;g[1]=-2147483647;size[1]=2;root=1;
    g[2]=2147483647;size[2]=siz[2]=siz[1]=1;fa[2]=1;t[1][1]=2;
    fo(i,1,n)
    {
        int opt,x;scanf("%d%d",&opt,&x);
        if(opt==1)//插入x 
        {
            int jy1=kthsmall(x,root);
            int jy2=kthbig(x,root);
            jy1=kth(jy1);jy2=kth(jy2);
            put(jy1,jy2,x);
        }
        if(opt==2)//删除x 
        {
            int jy1=kthsmall(x,root);
            int jy2=kthbig(x,root);
            jy1=kth(jy1);jy2=kth(jy2);
            splay(jy1,0);splay(jy2,jy1);
            siz[t[jy2][0]]--;update(t[jy2][0]);
            if(siz[t[jy2][0]]==0) t[jy2][0]=0;
            update(jy2);update(jy1);
        }
        if(opt==3)//查询x排名 
        {
            int jy=kth(x);
            splay(jy,0);
            printf("%d\n",size[t[jy][0]]);
        }
        if(opt==4)//查询排名x的数 
        {
            printf("%d\n",g[xth(x+1,root)]);
        }
        if(opt==5)//小于x的最大数 
        {
            int jy=kthsmall(x,root);
            printf("%d\n",jy);
        }
        if(opt==6)//大于x的最小数 
        {
            int jy=kthbig(x,root);
            printf("%d\n",jy);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值