www.cnblogs.com/shaokele/
luoguP3369 【模板】普通平衡树##
Time Limit: 1 Sec
Memory Limit: 128 MBDescription###
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1.插入 (x) 数
2.删除 (x) 数(若有多个相同的数,因只删除一个)
3.查询 (x) 数的排名(排名定义为比当前数小的数的个数 (+1) 。若有多个相同的数,因输出最小的排名)
4.查询排名为 (x) 的数
5.求 (x) 的前驱(前驱定义为小于 (x) ,且最大的数)
6.求 (x) 的后继(后继定义为大于 (x) ,且最小的数)
Input###
第一行为 (n) ,表示操作的个数,下面 (n) 行每行有两个数 (opt) 和 (x) , (opt) 表示操作的序号( (1 leq opt leq 6) )
Output###
对于操作 (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
HINT
1.n的数据范围: $n leq 100000 $
2.每个数的数据范围: ([-{10}^7, {10}^7])
来源:Tyvj1728 原名:普通平衡树
在此鸣谢
题目地址: luoguP3369 【模板】普通平衡树
题目大意: 已经很简洁了
题解:
整理ing
直接Splay
参考
AC代码
#include <cstdio>
using namespace std;
const int N=1e5+5;
int Q,op,x,root,size;
int f[N],key[N],cnt[N],sz[N],T[N][2];
inline void clear(int x){
T[x][0]=T[x][1]=f[x]=key[x]=cnt[x]=sz[x]=0;
}
inline int get(int x){ //判断当前节点是他父节点的左儿子还是右儿子
return T[f[x]][1]==x;
}
inline void update(int x){
if(!x)return;
sz[x]=cnt[x];
if(T[x][0])sz[x]+=sz[T[x][0]];
if(T[x][1])sz[x]+=sz[T[x][1]];
}
inline void rotate(int x){ //x换上去
int old=f[x],older=f[old],which=get(x);
T[old][which]=T[x][which^1];f[T[x][which^1]]=old;
T[x][which^1]=old;f[old]=x;
f[x]=older;
if(older)T[older][T[older][1]==old]=x;
update(old);update(x);
}
inline void splay(int x){ //rotate到根
for(int fa;(fa=f[x]);rotate(x))
if(f[fa])rotate(get(fa)==get(x)?fa:x);
root=x;
}
inline void insert(int x){
if(!root){
root=++size;
T[root][0]=T[root][1]=f[root]=0;
key[root]=x;cnt[root]=1;
return;
}
int now=root,fa=0;
while(1){
if(key[now]==x){
cnt[now]++;
update(now);update(fa);
splay(now);
return;
}
fa=now;now=T[now][x>key[now]];
if(now==0){
size++;
T[size][0]=T[size][1]=0;
sz[size]=cnt[size]=1;key[size]=x;
f[size]=fa;T[fa][x>key[fa]]=size;
update(fa);
splay(size);
return;
}
}
}
inline int find(int x){ //x的排名
int res=1,now=root;
while(1){
if(x<key[now])now=T[now][0];
else{
res+=(T[now][0]?sz[T[now][0]]:0);
if(x==key[now]){
splay(now);
return res;
}
res+=cnt[now];
now=T[now][1];
}
}
}
inline int findx(int x){ //找到排名为x的点
int now=root;
while(1){
if(T[now][0] && x<=sz[T[now][0]])now=T[now][0];
else{
int tmp=(T[now][0]?sz[T[now][0]]:0)+cnt[now];
if(x<=tmp)return key[now];
x-=tmp;now=T[now][1];
}
}
}
inline int pre(){ //x的前驱
int now=T[root][0];
while(T[now][1])now=T[now][1];
return now;
}
inline int next(){ //x的后继
int now=T[root][1];
while(T[now][0])now=T[now][0];
return now;
}
inline void del(int x){
find(x); //将x旋到根
if(cnt[root]>1){cnt[root]--;return;} //不止有一个x的话,返回-1
//only one point
if(!T[root][0] && !T[root][1]){clear(root);root=0;return;}
//no left child
if(!T[root][0]){
int old=root;
root=T[root][1];
clear(old);f[root]=0;
return;
}
//no right child
if(!T[root][1]){
int old=root;
root=T[root][0];
clear(old);f[root]=0;
return;
}
//two children
int left=pre(),old=root;
splay(left);
f[T[old][1]]=root;
T[root][1]=T[old][1];
clear(old);
update(root);
}
int main(){
scanf("%d",&Q);
while(Q--){
scanf("%d%d",&op,&x);
if(op==1)insert(x);
if(op==2)del(x);
if(op==3)printf("%d
",find(x));
if(op==4)printf("%d
",findx(x));
if(op==5)insert(x),printf("%d
",key[pre()]),del(x);
if(op==6)insert(x),printf("%d
",key[next()]),del(x);
}
return 0;
}
作者:skl_win
出处:https://www.cnblogs.com/shaokele/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。