【题目来源】
https://www.luogu.com.cn/problem/P3369
https://www.acwing.com/problem/content/255/
【题目描述】
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
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≤n≤100000,所有数均在 −10^7 到 10^7 内。
【输入样例】
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
【输出样例】
106465
84185
492737
【算法分析】
● FHQ−Treap,也称非旋 Treap,由范浩强提出。顾名思义,FHQ−Treap 就是不需要通过旋转,而是通过分裂(split)与合并(merge)维护的 Treap。FHQ−Treap 与 Treap 的另外一个区别是 FHQ−Treap 可持久化。
● FHQ-Treap 的高明之处在于所有的操作都只用到了分裂(split)与合并(merge)这两个基本操作。
● 本题的 Treap 树实现参见:https://blog.csdn.net/hnjzsyjyj/article/details/138482439
● 本题的替罪羊树实现参见:https://blog.csdn.net/hnjzsyjyj/article/details/128647972
【算法代码】
#include <bits/stdc++.h>
using namespace std;
const int maxn=500005;
int ch[maxn][2],val[maxn],pri[maxn],cnt[maxn],id;
int read() { //fast read
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9') { //!isdigit(c)
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9') { //isdigit(c)
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
void update(int x) {
cnt[x]=1+cnt[ch[x][0]]+cnt[ch[x][1]];
}
int new_node(int v) {
cnt[++id]=1;
val[id]=v;
pri[id]=rand();
return id;
}
int merge(int x,int y) {
if (!x || !y) return x+y;
if (pri[x]<pri[y]) {
ch[x][1]=merge(ch[x][1],y);
update(x);
return x;
} else {
ch[y][0]=merge(x,ch[y][0]);
update(y);
return y;
}
}
void split(int cur,int k,int &x,int &y) {
if (!cur) x=y=0;
else {
if (val[cur]<=k)
x=cur,split(ch[cur][1],k,ch[cur][1],y);
else
y=cur,split(ch[cur][0],k,x,ch[cur][0]);
update(cur);
}
}
int kth(int cur,int k) {
while(1) {
if (k<=cnt[ch[cur][0]])
cur=ch[cur][0];
else if (k==cnt[ch[cur][0]]+1)
return cur;
else
k-=cnt[ch[cur][0]]+1,cur=ch[cur][1];
}
}
int main() {
int T,opt,x,y,z,a,b,root=0;
T=read();
while(T--) {
opt=read(),a=read();
if (opt==1) {
split(root,a,x,y);
root=merge(merge(x,new_node(a)),y);
} else if (opt==2) {
split(root,a,x,z);
split(x,a-1,x,y);
y=merge(ch[y][0],ch[y][1]);
root=merge(merge(x,y),z);
} else if (opt==3) {
split(root,a-1,x,y);
printf("%d\n",cnt[x]+1);
root=merge(x,y);
} else if (opt==4)
printf("%d\n",val[kth(root,a)]);
else if (opt==5) {
split(root,a-1,x,y);
printf("%d\n",val[kth(x,cnt[x])]);
root=merge(x,y);
} else {
split(root,a,x,y);
printf("%d\n",val[kth(y,1)]);
root=merge(x,y);
}
}
return 0;
}
/*
in:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
out:
106465
84185
492737
*/
【参考文献】
https://www.luogu.com.cn/blog/85514/fhq-treap-xue-xi-bi-ji
https://blog.csdn.net/m0_51796369/article/details/119834710
http://www.yhzq-blog.cc/fhq-treap%E6%80%BB%E7%BB%93/
https://www.luogu.com.cn/problem/P3369
https://www.acwing.com/problem/content/255/
https://www.acwing.com/blog/content/4455/
https://www.acwing.com/problem/content/description/268/
https://blog.csdn.net/weixin_44316314/article/details/114155492