Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]

题目链接:

https://www.lydsy.com/JudgeOnline/problem.php?id=3224

https://www.luogu.org/problemnew/show/P3369

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.每个数的数据范围:[-2e9,2e9]

 

可能最近搞平衡二叉搜索树上瘾了?搞完替罪羊树再来搞搞无旋Treap。

关于无旋Treap:

我们已经知道了Treap是怎么写的:BZOJ 3224 - 普通平衡树 - [Treap][Splay]

我们知道,普通的Treap是要zigzag的,而无旋Treap顾名思义就是不需要zigzag。

无旋Treap最基本的(也是核心的)操作只有两种,一种 $Merge$,一种 $Split$。

  $Split(x,k,a,b)$ 拆分操作:按照一个判定值 $k$ 将一个Treap $x$ 拆成两个Treap $a,b$(左树和右树),满足左树的所有值均小于等于 $k$,右树的所有值都大于 $k$。

  $Merge(x,a,b)$ 合并操作:将两个Treap $a,b$ (满足 $a$ 中所有元素均小于 $b$ 中所有元素),合并成一个Treap $x$。合并的原则是节点的堆权值满足堆性质,所以是一种平衡树。

另外,与普通Treap不同的是,每个节点均只存一个元素;也就是说,若存在若干个相同元素,会有若干个节点,而非一个节点用 $cnt$ 去记录。

 

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=INT_MAX;
const int maxn=1e5+10;

/******************************** FHQ Treap - st ********************************/
int root,nodecnt;
int ch[maxn][2];
int key[maxn],dat[maxn];
int siz[maxn];
int NewNode(int val)
{
    int x=++nodecnt;
    key[x]=val, dat[x]=rand();
    siz[x]=1, ch[x][0]=ch[x][1]=0;
    return x;
}
void Pushup(int x) {
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void Init()
{
    root=nodecnt=0;
    key[0]=dat[0]=0;
    siz[0]=0, ch[0][0]=ch[0][1]=0;
}
void Split(int x,int k,int &a,int &b)
{
    if(x==0)
    {
        a=b=0;
        return;
    }
    if(key[x]<=k) a=x, Split(ch[x][1],k,ch[a][1],b);
    else b=x, Split(ch[x][0],k,a,ch[b][0]);
    Pushup(x);
}
void Merge(int &x,int a,int b)
{
    if(a==0 || b==0)
    {
        x=a+b;
        return;
    }
    if(dat[a]<dat[b]) x=a, Merge(ch[x][1],ch[a][1],b);
    else x=b, Merge(ch[x][0],a,ch[b][0]);
    Pushup(x);
}

int GetRank(int val)
{
    int a=0,b=0;
    Split(root,val-1,a,b);
    int res=siz[a]+1;
    Merge(root,a,b);
    return res;
}
int GetKth(int x,int k)
{
    if(x==0) return INF;
    if(siz[ch[x][0]]+1==k) return key[x];
    if(siz[ch[x][0]]>=k) return GetKth(ch[x][0],k);
    else return GetKth(ch[x][1],k-siz[ch[x][0]]-1);
}
void Insert(int val)
{
    int a=0,b=0;
    Split(root,val,a,b);
    Merge(a,a,NewNode(val));
    Merge(root,a,b);
}
void Remove(int val)
{
    int a=0,b=0,c=0;
    Split(root,val,a,b);
    Split(a,val-1,a,c);
    Merge(c,ch[c][0],ch[c][1]);
    Merge(a,a,c);
    Merge(root,a,b);
}
int GetPre(int val)
{
    int a=0,b=0;
    Split(root,val-1,a,b);
    int res=GetKth(a,siz[a]);
    Merge(root,a,b);
    return res;
}
int GetNxt(int val)
{
    int a=0,b=0;
    Split(root,val,a,b);
    int res=GetKth(b,1);
    Merge(root,a,b);
    return res;
}
/******************************** FHQ Treap - ed ********************************/

int main()
{
    int n,opt,x;
    scanf("%d",&n);
    Init();
    while(n--)
    {
        scanf("%d%d",&opt,&x);
        if(opt==1) Insert(x);
        if(opt==2) Remove(x);
        if(opt==3) printf("%d\n",GetRank(x));
        if(opt==4) printf("%d\n",GetKth(root,x));
        if(opt==5) printf("%d\n",GetPre(x));
        if(opt==6) printf("%d\n",GetNxt(x));
    }
}

无旋Treap真的太好写了啊!!!QAQ又好写又好懂!!!比替罪羊树好多了QAQ!!!

posted @ 2018-12-06 15:18  Dilthey  阅读(305)  评论(0编辑  收藏  举报