洛谷P3369 平衡树Treap
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入 xx 数
- 删除 xx 数(若有多个相同的数,因只删除一个)
- 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 )
- 查询排名为 xx 的数
- 求 xx 的前驱(前驱定义为小于 xx,且最大的数)
- 求 xx 的后继(后继定义为大于 xx,且最小的数)
输入格式
第一行为 nn,表示操作的个数,下面 nn 行每行有两个数 \text{opt}opt 和 xx,\text{opt}opt 表示操作的序号( 1 \leq \text{opt} \leq 61≤opt≤6 )
输出格式
对于操作 3,4,5,63,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
说明/提示
【数据范围】
对于 100\%100% 的数据,1\le n \le 10^51≤n≤105,|x| \le 10^7∣x∣≤107
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//https://www.luogu.com.cn/problem/P3369 #include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; const int inf=0x3f3f3f3f; int sum ,R; int size[maxn],v[maxn],num[maxn],rd[maxn],son[maxn][2]; void push_up(int p) { size[p]=size[son[p][0]]+size[son[p][1]]+num[p]; } void rotate(int &p,int d) { int k=son[p][d^1]; son[p][d^1]=son[k][d]; son[k][d]=p; push_up(p); push_up(k); p=k; } void ins(int &p,int x) { if (!p) { p=++sum; size[p]=num[p]=1; v[p]=x; rd[p]=rand(); return; } if (v[p]==x) { num[p]++; size[p]++; return; } int d=(x>v[p]); ins(son[p][d],x); if (rd[p]<rd[son[p][d]]) rotate(p,d^1); push_up(p); } void del(int &p,int x) { if (!p) return; if (x<v[p]) del(son[p][0],x); else if (x>v[p]) del(son[p][1],x); else { if (!son[p][0] && !son[p][1]) { num[p]--; size[p]--; if (num[p]==0) p=0; } else if (son[p][0] && !son[p][1]) { rotate(p,1); del(son[p][1],x); } else if (!son[p][0] && son[p][1]) { rotate(p,0); del(son[p][0],x); } else if (son[p][0] && son[p][1]) { int d=(rd[son[p][0]]>rd[son[p][1]]); rotate(p,d); del(son[p][d],x); } } push_up(p); } int rnk(int p,int x) { if (!p) return 0; if (v[p]==x) return size[son[p][0]]+1; if (v[p]<x) return size[son[p][0]]+num[p]+rnk(son[p][1],x); if (v[p]>x) return rnk(son[p][0],x); } int find(int p,int x) { if (!p) return 0; if (size[son[p][0]]>=x) return find(son[p][0],x); else if (size[son[p][0]]+num[p]<x) return find(son[p][1],x-num[p]-size[son[p][0]]); else return v[p]; } int pre(int p,int x) { if (!p) return -inf; if (v[p]>=x) return pre(son[p][0],x); else return max(v[p],pre(son[p][1],x)); } int suc(int p,int x) { if (!p) return inf; if (v[p]<=x) return suc(son[p][1],x); else return min(v[p],suc(son[p][0],x)); } int main() { int T; scanf("%d",&T); while(T--) { int opt,x; scanf("%d%d",&opt,&x); if (opt==1) ins(R,x); else if (opt==2) del(R,x); else if (opt==3) printf("%d\n",rnk(R,x)); else if (opt==4) printf("%d\n",find(R,x)); else if (opt==5) printf("%d\n",pre(R,x)); else if (opt==6) printf("%d\n",suc(R,x)); } return 0; }