P3369-[模板]普通平衡树【无旋Treap】
正题
题目链接:https://www.luogu.com.cn/problem/P3369
题目大意
一个空可重集,要求支持
- 插入一个数\(x\)
- 删除一个数\(x\)
- 询问一个数\(x\)的排名
- 询问排名第\(x\)的数字
- 询问\(x\)的前驱
- 询问\(x\)的后继
\(1\leq n\leq 10^5,1\leq |x|\leq 10^7\)
解题思路
拖了两年的FHQ终于还是写了(还有二逼平衡树拖到现在还没写)。
看的是别人博客学的:https://www.luogu.com.cn/blog/85514/fhq-treap-xue-xi-bi-ji
具体特点就是结构固定我通过分裂的方式直接让节点插入在对应的位置,这样就不需要旋转来调整结构了。
还有相同的数字不是存在同一个节点而是分开存的,所以同一个数字可以有多个节点。
时间复杂度:\(O(n\log n)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int T,root;
struct FHQ{
int cnt,w[N],rnk[N],siz[N],t[N][2];
int NewNode(int val){
w[++cnt]=val;siz[cnt]=1;
rnk[cnt]=rand();
return cnt;
}
void PushUp(int x){
siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;
return;
}
void Split(int &x,int &y,int p,int val){
if(!p){x=y=0;return;}
if(w[p]<=val)x=p,Split(t[x][1],y,t[p][1],val);
else y=p,Split(x,t[y][0],t[p][0],val);
PushUp(p);return;
}
int Merge(int x,int y){
if(!x||!y)return x|y;
if(rnk[x]<rnk[y]){
t[x][1]=Merge(t[x][1],y);
PushUp(x);return x;
}
else{
t[y][0]=Merge(x,t[y][0]);
PushUp(y);return y;
}
}
int Find(int x,int k){
if(siz[t[x][0]]>=k)return Find(t[x][0],k);
if(siz[t[x][0]]+1==k)return x;
return Find(t[x][1],k-siz[t[x][0]]-1);
}
void Insert(int w){
int x,y;Split(x,y,root,w);
root=Merge(Merge(x,NewNode(w)),y);
}
void Delete(int w){
int x,y,z;
Split(x,y,root,w-1);
Split(y,z,y,w);
y=Merge(t[y][0],t[y][1]);
root=Merge(Merge(x,y),z);
return;
}
int GetRank(int w){
int x,y,ans;
Split(x,y,root,w-1);
ans=siz[x]+1;
root=Merge(x,y);
return ans;
}
int GetVal(int r)
{return w[Find(root,r)];}
int GetPre(int r){
int x,y,ans;
Split(x,y,root,r-1);
ans=w[Find(x,siz[x])];
root=Merge(x,y);
return ans;
}
int GetNxt(int r){
int x,y,ans;
Split(x,y,root,r);
ans=w[Find(y,1)];
root=Merge(x,y);
return ans;
}
}Tr;
int main()
{
scanf("%d",&T);
Tr.NewNode(-1e9);Tr.NewNode(1e9);
root=Tr.Merge(1,2);
while(T--){
int op,w;
scanf("%d%d",&op,&w);
if(op==1)Tr.Insert(w);
else if(op==2)Tr.Delete(w);
else if(op==3)printf("%d\n",Tr.GetRank(w)-1);
else if(op==4)printf("%d\n",Tr.GetVal(w+1));
else if(op==5)printf("%d\n",Tr.GetPre(w));
else if(op==6)printf("%d\n",Tr.GetNxt(w));
}
}