普通的平衡树

https://vjudge.net/contest/238179#problem/D

#include<iostream>
#include<algorithm>
#include<string>
#include<stdio.h>
#include<map>
using namespace std;
const int N=110000;
int key[N],father[N],ch[N][2],Size[N],cnt[N];
int root,tot,pre,next;

void Newnode(int &r,int pre,int k)
{
    r=++tot;
    father[r]=pre;
    key[r]=k;
    ch[r][0]=ch[r][1]=0;
    Size[r]=1;
    cnt[r]=1;
}
void clear(int x)
{
    Size[x] = father[x] = ch[x][0] = ch[x][1] = cnt[x] = key[x] = 0;
}
void up(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 kind)
{
    int y=father[x];
    ch[y][!kind]=ch[x][kind];
    father[ch[x][kind]]=y;
    if(father[y])
        ch[father[y]][ch[father[y]][1]==y]=x;
    father[x]=father[y];
    ch[x][kind]=y;
    father[y]=x;
    up(y);
}
void splay(int x,int goal)
{
    while(father[x]!=goal)
    {
        int y=father[x];
        if(father[y]==goal)
            Rotate(x,ch[y][0]==x);
        else
        {
            int kind=(ch[father[y]][0]==y);
            if(ch[y][kind]==x)
            {
                Rotate(x,!kind);
                Rotate(x,kind);
            }
            else
            {
                Rotate(y,kind);
                Rotate(x,kind);
            }
        }
    }
    if(goal==0)
        root=x;
    up(x);
}
void Insert(int x)
{
    if(root==0)
    {
        Newnode(root,0,x);
        return;
    }
    int now=root;
    while(true)
    {
        Size[now]++;
        if(x==key[now])
        {
            cnt[now]++;
            return;
        }
        if(ch[now][key[now]<x]==0)//之前错误的原因是
                                 //int y=ch[now][key[now]<x];Newnode(y,now,x);
                                 //这样就导致ch[now][key[now]<x]值没有改变,就超时了
        {
            Newnode(ch[now][key[now]<x],now,x);
            now=ch[now][key[now]<x];
            break;
        }
        now=ch[now][key[now]<x];
    }
    splay(now,0);
}

void del(int x)
{
    int r=root;
    while(1)
    {
        if(key[r]==x)
            break;
        r=ch[r][key[r]<x];
    }
    splay(r,0);//应该先让r成为根节点,当cnt[r]>1,才能直接--,因为如果不改变r上面的所有节点的值都改变了,很麻烦
    if(cnt[r]>1)
    {
        cnt[r]--;
        Size[r]--;
        return;
    }
    int rr=root;
    if(ch[r][0]&&!ch[r][1])
    {
        father[ch[r][0]]=0;
        root=ch[r][0];
        clear(rr);
    }
    else if(!ch[r][0]&&ch[r][1])
    {
        father[ch[r][1]]=0;
        root=ch[r][1];
        clear(rr);
    }
    else if(!ch[r][0]&&!ch[r][1])
    {
        root=0;
        clear(rr);
    }
    else
    {
        int k=ch[r][1];
        while(ch[k][0])
        {
            k=ch[k][0];
        }
        splay(k,root);
        ch[k][0]=ch[root][0];
        father[ch[root][0]]=k;
        father[k]=0;
        root=k;
        clear(rr);
        up(root);//修改完根节点,改变根节点的size;
    }
}
void Get_pre(int i,int x)
{
    if(i==0)
        return ;
    if(key[i]<x)
    {
        pre=key[i];
        Get_pre(ch[i][1],x);
    }
    else
        Get_pre(ch[i][0],x);
}

void Get_next(int i,int x)
{
    if(i==0)
        return;
    if(key[i]>x)
    {
        next=key[i];
        Get_next(ch[i][0],x);
    }
    else
        Get_next(ch[i][1],x);
}

int Find_x(int v)//这个函数刚开始就写错了,,,,,
{
    int now = root, ans = 0;
    while(1)
    {
        if(v < key[now])
            now = ch[now][0]; //左
        else
        {
            if(ch[now][0])
                ans += Size[ch[now][0]];
            if(v == key[now])
            {
                splay(now,0);
                return ans + 1;
            }
            ans += cnt[now];
            now = ch[now][1];//右
        }
    }
}

int Find_k(int i,int k)
{
    if(i==0)
        return -1;
    if(Size[ch[i][0]]>=k)
        return Find_k(ch[i][0],k);
    if(Size[ch[i][0]]+cnt[i]>=k)
        return key[i];
    return Find_k(ch[i][1],k-Size[ch[i][0]]-cnt[i]);
}


int main()
{
    int n;
    scanf("%d",&n);
    root=tot=0;
    for(int i=1; i<=n; i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a==1)
            Insert(b);
        else if(a==2)
            del(b);
        else if(a==3)
            printf("%d\n",Find_x(b));
        else if(a==4)
            printf("%d\n",Find_k(root,b));
        else if(a==5)
        {
            Get_pre(root,b);
            printf("%d\n",pre);
        }
        else if(a==6)
        {
            Get_next(root,b);
            printf("%d\n",next);

        }

    }
    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值