P3369 【模板】普通平衡树(Treap/SBT)

时间:2022-05-10
本文章向大家介绍P3369 【模板】普通平衡树(Treap/SBT),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求x的后继(后继定义为大于x,且最小的数)

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

106465
84185
492737

说明

时空限制:1000ms,128M

1.n的数据范围:n<=100000

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

来源:Tyvj1728 原名:普通平衡树

在此鸣谢

FHQ Treap。。。

这是我迄今为止见过最神奇没有之一的数据结构!。

它可以用简单的两个非旋转操作模拟出BST的所有操作。

unbelievable。

有空要好好写一篇关于这个的博客

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<cstdlib>
  7 #include<ctime>
  8 using namespace std;
  9 const int MAXN=100001;
 10 static void read(int &n)
 11 {
 12     char c='+';int x=0;bool flag=0;
 13     while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;}
 14     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c-48);c=getchar();}
 15     flag==1?n=-x:n=x;
 16 }
 17 int ch[MAXN][3];// 0左孩子 1右孩子
 18 int val[MAXN];// 每一个点的权值
 19 int pri[MAXN];// 随机生成的附件权值
 20 int siz[MAXN];// 以i为节点的树的节点数量
 21 int sz;// 总结点的数量 
 22 void update(int x)
 23 {
 24     siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
 25 } 
 26 int new_node(int v)
 27 {
 28     siz[++sz]=1;// 新开辟一个节点
 29     val[sz]=v;
 30     pri[sz]=rand(); 
 31     return sz;
 32 }
 33 int merge(int x,int y)// 合并 
 34 {
 35     if(!x||!y)    return x+y;// x和y中必定有一个是0
 36     if(pri[x]<pri[y])// 把x加到左边的树上 
 37     {
 38         ch[x][1]=merge(ch[x][1],y);// 不懂的看GIF图 
 39         update(x);
 40         return x;
 41     } 
 42     else
 43     {
 44         ch[y][0]=merge(x,ch[y][0]);
 45         update(y);
 46         return y;
 47     }
 48 }
 49 void split(int now,int k,int &x,int &y)
 50 {
 51     if(!now) x=y=0;// 到达叶子节点
 52     else
 53     {
 54         if(val[now]<=k)// 分离右子树    
 55             x=now,split(ch[now][1],k,ch[now][1],y);
 56         else 
 57             y=now,split(ch[now][0],k,x,ch[now][0]);
 58         update(now);
 59     } 
 60 }
 61 int kth(int now,int k)// 查询排名 
 62 {
 63     while(1)
 64     {
 65         if(k<=siz[ch[now][0]])
 66             now=ch[now][0];// 在左子树中,且数量小于左子树的大小,迭代寻找
 67         else if(k==siz[ch[now][0]]+1)
 68             return now;// 找到了
 69         else 
 70             k-=siz[ch[now][0]]+1,now=ch[now][1];// 去右子树找 
 71     }
 72 }
 73 int main()
 74 {
 75     srand((unsigned)time(NULL));
 76     int n;
 77     read(n);
 78     int root=0,x,y,z;
 79     for(int i=1;i<=n;i++)
 80     {
 81         int how,a;
 82         read(how);read(a);
 83         if(how==1)// 插入 
 84         {
 85             split(root,a,x,y);
 86             root=merge(merge(x,new_node(a)),y);
 87         }
 88         else if(how==2)//删除x 
 89         {
 90             split(root,a,x,z);
 91             split(x,a-1,x,y);
 92             y=merge(ch[y][0],ch[y][1]);
 93             root=merge(merge(x,y),z);
 94         }
 95         else if(how==3)//查询x的排名 
 96         {
 97             split(root,a-1,x,y);
 98             printf("%dn",siz[x]+1);
 99             root=merge(x,y);
100         }
101         else if(how==4)// 查询排名为x的数 
102         {
103             printf("%dn",val[kth(root,a)]);
104         }
105         else if(how==5)// 求x的前驱 
106         {
107             split(root,a-1,x,y);
108             printf("%dn",val[kth(x,siz[x])]);
109             root=merge(x,y);
110         }
111         else if(how==6)// 求x的后继 
112         {
113             split(root,a,x,y);
114             printf("%dn",val[kth(y,1)]);
115             root=merge(x,y);
116         }
117     }
118     return 0;
119 }