这里想要深度学习Fhq treap,推荐通过b站学习,B站大佬 不分解的AgOH 讲的非常好,建议观看学习
大佬讲解视频
题目描述:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
插入x数
删除x数(若有多个相同的数,因只删除一个)
查询x数的排名(若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数)
求x的后继(后继定义为大于x,且最小的数)
输入描述:
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出描述:
对于操作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
具体代码:
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<random>
std::mt19937 rnd(233);
#define M 100010
using namespace std;
struct Node
{
int left,right;
int value,key;//值加索引
int size;//子树大小
}tree[M];
int cnt,node;
int x,y,z;
inline int newnode(int val)//建立新节点和节点信息的保存
{
tree[++cnt].value=val;
tree[cnt].key=rnd();
tree[cnt].size=1;
return cnt;
}
void update(int now)//更新子树的大小
{
tree[now].size=tree[tree[now].left].size+tree[tree[now].right].size+1;
}
void split(int now,int val,int& x,int& y)//x,y作为;两个返回值
{
if(!now)//如果当前你分裂的数不存在,返回两个不存在的数
x=y=0;
else
{
if(tree[now].value<=val)
{
x=now;//如果根节点比val小左子树肯定比val小
split(tree[now].right,val,tree[now].right,y);//对右子树进行递归操作
}
else
{
y=now;//如果根节点比val大右子树肯定比val大
split(tree[now].left,val,x,tree[now].left);//对左子树进行递归操作
}
update(now);
}
}
int merge(int x,int y)//合并
{
if(!x||!y)//如果xy有一个不存在那就返回另一个
{
return x+y;
}
if(tree[x].key>tree[y].key)//如果x节点的索引大于y节点的索引,父节点的优先级肯定大于所有子节点的优先级,那么合并的话y肯定在x的右下方
{//索引大说明x在y的上方
tree[x].right=merge(tree[x].right,y);
update(x);
return x;
}
else
{//x在y的左下方
tree[y].left=merge(x,tree[y].left);
update(y);
return y;
}
}
void ins(int val)//插入
{
split(node,val,x,y);//以val为中间值分裂
node=merge(merge(x,newnode(val)),y);//先合并x和val,在与y合并
//printf("%dm\n",node);
}
void del(int val)//删除
{
split(node,val,x,z);//按val把树分为x,z
split(x,val-1,x,y);//按val-1把x分为x,y,此时y中值全部等于val
y=merge(tree[y].left,tree[y].right);//删除y根节点的那个val,方法是将y等于y的左子树和右子树合并
node=merge(merge(x,y),z);
}
void getrank(int val)//查询val的排名
{
split(node,val-1,x,y);//此时x中全部为小于val的值
printf("%d\n",tree[x].size+1);//x子树的大小加1就是val的排名
node=merge(x,y);//合并回去
}
void getnum(int rank)
{
int now=node;
while(now)
{
if(tree[tree[now].left].size+1==rank)
break;
else if(tree[tree[now].left].size>=rank){
now=tree[now].left;
}
else
{
rank-=tree[tree[now].left].size+1;
now=tree[now].right;
}
}
printf("%d\n",tree[now].value);
}
void pre(int val)//找前驱
{
split(node,val-1,x,y);//以val-1分裂
int now=x;//x最右侧的值就是前驱
while(tree[now].right)//如果x里最右边不为空就继续找
{
now=tree[now].right;
}
printf("%d\n",tree[now].value);
node=merge(x,y);
}
void nxt(int val)//找后继
{
//printf("%d%d %d\n",x,y,node);
split(node,val,x,y);//以val分裂
int now=y;//y最左侧的值就是后继
while(tree[now].left)//如果y的最左侧不为空就继续找
{
now=tree[now].left;
}
printf("%d\n",tree[now].value);
node=merge(x,y);
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int m,k;
//printf("%d%d\n",x,y);
scanf("%d%d",&m,&k);
if(m==1)
{
ins(k);
continue;
}
if(m==2)
{
del(k);
continue;
}
if(m==3)
{
getrank(k);
continue;
}
if(m==4)
{
getnum(k);
continue;
}
if(m==5)
{
pre(k);
continue;
}
if(m==6)
{
nxt(k);
continue;
}
}
return 0;
}