洛谷 P3369 【模板】普通平衡树
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入 xx 数
- 删除 xx 数(若有多个相同的数,因只删除一个)
- 查询 xx 数的排名(排名定义为比当前数小的数的个数 +1+1 )
- 查询排名为 xx 的数
- 求 xx 的前驱(前驱定义为小于 xx,且最大的数)
- 求 xx 的后继(后继定义为大于 xx,且最小的数)
输入格式
第一行为 nn,表示操作的个数,下面 nn 行每行有两个数 ext{opt}opt 和 xx, ext{opt}opt 表示操作的序号( 1 leq ext{opt} leq 61≤opt≤6 )
输出格式
对于操作 3,4,5,63,4,5,6 每行输出一个数,表示对应答案
说明/提示
【数据范围】
对于 100%100% 的数据,1le n le 10^51≤n≤105,|x| le 10^7∣x∣≤107
来源:Tyvj1728 原名:普通平衡树
在此鸣谢
题解:
题如其名。
平衡树不会的请走这边:
蒟蒻只学了两种平衡树qwq...蒟蒻太菜了。
最后还是用SplayAC的:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int n;
int tot,root;
int val[maxn],size[maxn],cnt[maxn],fa[maxn],ch[maxn][2];
void maintain(int x)
{
size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];
}
int find(int x)
{
int pos=root;
while(val[pos]!=x)
pos=ch[pos][x>val[pos]];
return pos;
}
int get(int x)
{
int f=fa[x];
return ch[f][1]==x;
}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int k=get(x);//k表示x是y的什么儿子
ch[y][k]=ch[x][k^1],fa[ch[y][k]]=y;
ch[x][k^1]=y,fa[y]=x,fa[x]=z;
if(z)
ch[z][ch[z][1]==y]=x;
maintain(y),maintain(x);
}
void splay(int x,int &goal)
{
int f=fa[goal];
while(fa[x]!=f)
{
if(fa[fa[x]]!=f)
rotate(get(x)==get(fa[x])?fa[x]:x);
rotate(x);
}
goal=x;
}
void insert(int x)
{
if(!root)
{
++tot;
root=tot;
val[root]=x;
cnt[root]=1;
maintain(root);
return;
}
int pos,f;
pos=f=root;
while(pos && val[pos]!=x)
f=pos,pos=ch[pos][x>val[pos]];
if(!pos)
{
++tot;
cnt[tot]=1;
val[tot]=x;
fa[tot]=f;
ch[f][x>val[f]]=tot;
maintain(tot);
splay(tot,root);
return;
}
++cnt[pos];
maintain(pos);
splay(pos,root);
}
void del(int x)
{
int pos=find(x);
splay(pos,root);
if(cnt[root]>1)
{
cnt[root]--;
maintain(root);
return;
}
if((!ch[root][0])&&(!ch[root][1]))
root=0;
else if(!ch[root][0])
root=ch[root][1],fa[root]=0;
else if(!ch[root][1])
root=ch[root][0],fa[root]=0;
else
{
pos=ch[root][0];
while(ch[pos][1])
pos=ch[pos][1];
splay(pos,ch[root][0]);
ch[pos][1]=ch[root][1];
fa[ch[root][1]]=pos,fa[pos]=0;
maintain(pos);
root=pos;
}
}
int rank(int x)
{
int pos=find(x);
splay(pos,root);
return size[ch[root][0]]+1;
}
int kth(int x)
{
int pos=root;
while(1)
{
if(x<=size[ch[pos][0]])
pos=ch[pos][0];
else
{
x-=(size[ch[pos][0]]+cnt[pos]);
if(x<=0)
{
splay(pos,root);
return val[pos];
}
pos=ch[pos][1];
}
}
}
int pre(int x)
{
int ans;
int pos=root;
while(pos)
{
if(x>val[pos])
{
ans=val[pos];
pos=ch[pos][1];
}
else
pos=ch[pos][0];
}
return ans;
}
int nxt(int x)
{
int ans;
int pos=root;
while(pos)
{
if(x<val[pos])
{
ans=val[pos];
pos=ch[pos][0];
}
else
pos=ch[pos][1];
}
return ans;
}
int main()
{
scanf("%d",&n);
while(n--)
{
int opt,x;
scanf("%d%d",&opt,&x);
if(opt==1)
insert(x);
if(opt==2)
del(x);
if(opt==3)
printf("%d
",rank(x));
if(opt==4)
printf("%d
",kth(x));
if(opt==5)
printf("%d
",pre(x));
if(opt==6)
printf("%d
",nxt(x));
}
return 0;
}