[BZOJ3224][SPLAY]普通平衡树

本文介绍了一种基于Splay树的数据结构实现方法,包括插入、删除、查询等操作,并通过具体实例展示了如何解决特定问题。文章深入探讨了Splay树的旋转、查找等关键算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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]

真正意义上第一道手写的SPLAY,还是出了很多BUG
注意题目找前驱后驱那些数不一定被插入了序列中,所以需先插入再查找,简直坑到爆,调了半天才发现题理解错了

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1e5+5,INF=0x7f7f7f7f;
int n,maxnode,root;
queue<int>que;
struct Node
{
    int val,size,cnt,fa,ch[2];
}node[maxn];
#define val(x) node[x].val
#define size(x) node[x].size
#define cnt(x) node[x].cnt
#define ch(x,d) node[x].ch[d]
#define fa(x) node[x].fa
void recycle(int x)
{
    que.push(x);
}
int require()
{
    int ret;
    if (!que.empty()) ret=que.front(),que.pop();
    else ret=++maxnode;
    return ret;
}
void update(int x)
{
    size(x)=cnt(x);
    int L=ch(x,0),R=ch(x,1);
    if (L) size(x)+=size(L);
    if (R) size(x)+=size(R);
}
void rotate(int x,int &rt)
{
    int y=fa(x),z=fa(y),L=ch(y,1)==x,R=L^1;
    if (y==rt) rt=x;
    else ch(z,ch(z,1)==y)=x;
    fa(ch(x,R))=y; fa(y)=x; fa(x)=z; ch(y,L)=ch(x,R); ch(x,R)=y;
    update(y); update(x);
}
void splay(int x,int &rt)
{   
    while (x^rt)
    {
        int y=fa(x),z=fa(y);
        if (y^rt)
          if ((x==ch(y,0)^(y==ch(z,0)))) rotate(x,rt);
          else rotate(y,rt);
        rotate(x,root);
    }
}
void insert(int key)
{
    if (!root) {root=require();val(root)=key;cnt(root)=size(root)=1;return;}
    int x=root,y=0;
    while (x&&(key^val(x))) y=x,x=ch(x,key>val(x));
    if (x) cnt(x)++;
    else x=require(),val(x)=key,cnt(x)=size(x)=1,ch(y,key>val(y))=x,fa(x)=y;
    splay(x,root);
}
int find(int key)
{
    int x=root;
    while (key^val(x)) x=ch(x,key>val(x));
    return x;
}
int pre(int x)
{
    splay(x,root);
    x=ch(x,0);
    while (ch(x,1)) x=ch(x,1);
    return x;
}
int nxt(int x)
{
    splay(x,root);
    x=ch(x,1);
    while (ch(x,0)) x=ch(x,0);
    return x;
}
void erase(int key)
{
    int x=find(key);
    splay(x,root);
    cnt(x)--;
    if (cnt(x)) return ;
    int L=pre(x),R=nxt(x);
    splay(L,root); splay(R,ch(L,1));
    ch(R,0)=0; recycle(x);
    update(R); update(L);
}
int rank(int x)
{
    splay(x,root);
    return size(ch(x,0))+1;
}
int query(int x,int rk)
{
    int Lsize=size(ch(x,0));
    if (rk<=Lsize) return query(ch(x,0),rk);
    if (rk<=Lsize+cnt(x)) return val(x);
    return query(ch(x,1),rk-Lsize-cnt(x));
}
int Pre(int key)
{
    insert(key);
    int rt=pre(root);
    erase(key);
    return rt;
}
int Nxt(int key)
{
    insert(key);
    int rt=nxt(root);
    erase(key);
    return rt;
}
int main()
{
//  freopen("splay.in","r",stdin);
    scanf("%d",&n);
    insert(INF); insert(-INF);
    while (n--)
    {
        int op,x;
        scanf("%d%d",&op,&x);
        switch (op)
        {
            case 1:insert(x);break;
            case 2:erase(x);break;
            case 3:printf("%d\n",rank(find(x))-1);break;
            case 4:printf("%d\n",query(root,x+1));break;
            case 5:printf("%d\n",val(Pre(x)));break;
            case 6:printf("%d\n",val(Nxt(x)));break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值