题面:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数
下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
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
Solution:
平衡树模板题
因为需要查找排名,我们记录一个size[i]代表以i为根的子树的大小,因为treap满足二叉查找树的性质,所以就很好搞。
因为可能会出现重复,所以我们可以再定义一个num来记录数值x在树中的个数
详见代码
Code:
treap版
#include<bits/stdc++.h>
#define N 100001
#define inf 1926081700
using namespace std;
int n;
struct treap{
#define ls tree[q].l
#define rs tree[q].r
struct dqy{
int l,r;
int val,key;
int num,size;
}tree[N];
int root,tot;
int add(int v){
tree[++tot].val=v;
tree[tot].key=rand();
tree[tot].num=tree[tot].size=1;
return tot;
}
void update(int q){
tree[q].size=tree[ls].size+tree[rs].size+tree[q].num;
}//更新自己
void build(){
add(-inf),add(inf);
root=1;tree[1].r=2;
update(1);
}
int getrank(int q,int v){
if(q==0)return 0;
if(tree[q].val==v)return tree[ls].size+1;//左子树上的点必定小于自己
if(tree[q].val>v)return getrank(ls,v);//如果比自己小,跳到左子树上去找
return getrank(rs,v)+tree[ls].size+tree[q].num;
//否则跳到右子树,因为右子上的点必定大于左子树和父亲,所以还要加上左子树的大小和父亲的数量
}//查找排名
int getval(int q,int rk){
if(q==0)return inf;
if(tree[ls].size>=rk)return getval(ls,rk);//左子树小于自己,所以直接跳到左子树找
if(tree[ls].size+tree[q].num>=rk)return tree[q].val;
//因为不在左子树上,又在左子树和自己之间,所以肯定是自己
return getval(rs,rk-tree[ls].size-tree[q].num); //否则跳到右子树上找
}//查找权值
void zig(int &q){
int tmp=ls;
ls=tree[tmp].r;tree[tmp].r=q;q=tmp;
update(rs),update(q);
}//右旋
void zag(int &q){
int tmp=rs;
rs=tree[tmp].l;tree[tmp].l=q;q=tmp;
update(ls),update(q);
}//左旋
void insert(int &q,int v){
if(q==0){
q=add(v);
return ;
}//没有这个点就新建一个点出来
if(v==tree[q].val){
tree[q].num++;
update(q);
return ;
}//有这个点就直接给这个点的num++就可以了
if(v<tree[q].val){
insert(ls,v);
if(tree[q].key<tree[ls].key)zig(q);
}
else {
insert(rs,v);
if(tree[q].key<tree[rs].key)zag(q);
}
//找有没有这个点
update(q);
}
int precursor(int v){
int ans=1;
int q=root;
while(q){
if(v==tree[q].val){
if(ls>0){
q=ls;
while(rs>0)q=rs;
ans=q;
}
break;
}//要严格小于
if(tree[q].val<v&&tree[q].val>tree[ans].val)ans=q;
q=v<tree[q].val?ls:rs;
}
return tree[ans].val;
}//前驱
int successor(int v){
int ans=2;
int q=root;
while(q){
if(v==tree[q].val){
if(rs>0){
q=rs;
while(ls>0)q=ls;
ans=q;
}
break;
}//要严格大于
if(tree[q].val>v&&tree[q].val<tree[ans].val)ans=q;
q=v<tree[q].val?ls:rs;
}
return tree[ans].val;
}//后继
void remove(int &q,int v){
if(q==0)return ;
if(v==tree[q].val){//存在过这个点
if(tree[q].num>1){
tree[q].num--,update(q);
return ;
}//如果有这个点,直接num--
if(ls||rs){
if(rs==0||tree[ls].key>tree[rs].key)zig(q),remove(rs,v);
else zag(q),remove(ls,v);
update(q);
}//否则跳到子树上去找
else q=0;
return ;
}
v<tree[q].val?remove(ls,v):remove(rs,v);//跳到子树上去找
update(q);
}
}T;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int main(){
n=read();T.build();
for(int i=1;i<=n;i++){
int opt=read(),x=read();
switch(opt){
case 1:
T.insert(T.root,x);
break;
case 2:
T.remove(T.root,x);
break;
case 3:
printf("%d
",T.getrank(T.root,x)-1);//一开始插入了最值,所以要减一
break;
case 4:
printf("%d
",T.getval(T.root,x+1));
//因为是严格大于小于,所以要给排名加一
break;
case 5:
printf("%d
",T.precursor(x));
break;
default :
printf("%d
",T.successor(x));
break;
}
}
return 0;
}
Splay版:
#include<bits/stdc++.h>
#define N 1000001
#define inf 19260817
using namespace std;
struct Splay{
#define ls tree[q].son[0]
#define rs tree[q].son[1]
int root,tot;
struct dqy{
int fa;
int son[2];
int cnt,val,size;
}tree[N];
int newnode(int v){
tree[++tot].val=v;
tree[tot].size=tree[tot].cnt=1;
return tot;
}
void update(int q){tree[q].size=tree[ls].size+tree[rs].size+tree[q].cnt;}
int t(int x){return tree[tree[x].fa].son[1]==x;}
int find(int v){
int q=root;
while(tree[q].val!=v){
if(tree[q].val>v){if(ls)q=ls;else break;}
if(tree[q].val<v){if(rs)q=rs;else break;}
}
return q;
}
void rotate(int q){
int ret=t(q),f=tree[q].fa,s=tree[q].son[ret^1];
tree[f].son[ret]=s;if(s)tree[s].fa=f;tree[q].son[ret^1]=f;
tree[q].fa=tree[f].fa;if(tree[f].fa)tree[tree[f].fa].son[t(f)]=q;
tree[f].fa=q;update(f);update(q);
}
void splay(int q){
while(tree[q].fa){
if(tree[tree[q].fa].fa)
if(t(tree[q].fa)==t(q))rotate(tree[q].fa);
rotate(q);
}
root=q;
}
void ins(int v){
if(!root){root=newnode(v);return ;}
int q=find(v);
if(tree[q].val==v){tree[q].cnt++;tree[q].size++;splay(q);return ;}
tree[newnode(v)].fa=q;tree[q].son[v>tree[q].val]=tot;
splay(tot);
}
void Delete(int v){
if(!root)return ;
int q=find(v);splay(q);
if(tree[q].val!=v||(--tree[q].cnt)){tree[q].size--;return ;}
if(!ls&&!rs){root=0;return ;}
if(!ls){root=rs;tree[rs].fa=0;return ;}
if(!rs){root=ls;tree[ls].fa=0;return ;}
int tmp=ls;while(tree[tmp].son[1])tmp=tree[tmp].son[1];
tree[ls].fa=0;splay(tmp);
tree[root].son[1]=rs;tree[rs].fa=root;
}
int getrk(int v){
int q=find(v);splay(q);
if(tree[q].val>=v)return tree[ls].size+1;
return tree[ls].size+tree[q].cnt+1;
}
int getval(int rk){
int q=root;
while(rk){
if(tree[ls].size>=rk)q=ls;
else if(tree[ls].size+tree[q].cnt>=rk)break;
else rk-=tree[ls].size+tree[q].cnt,q=rs;
}
return tree[q].val;
}
int precusor(int v){
int q=find(v);splay(q);
if(tree[q].val<v)return tree[q].val;
q=ls;while(rs)q=rs;
return tree[q].val;
}
int succesor(int v){
int q=find(v);splay(q);
if(tree[q].val>v)return tree[q].val;
q=rs;while(ls)q=ls;
return tree[q].val;
}
}T;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int main(){
int n=read();
for(int i=1;i<=n;i++){
int opt=read(),v;
switch(opt){
case 1:v=read();T.ins(v);break;
case 2:v=read();T.Delete(v);break;
case 3:v=read();printf("%d
",T.getrk(v));break;
case 4:v=read();printf("%d
",T.getval(v));break;
case 5:v=read();printf("%d
",T.precusor(v));break;
case 6:v=read();printf("%d
",T.succesor(v));break;
}
}
return 0;
}