题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
插入 (x) 数
删除 (x) 数(若有多个相同的数,因只删除一个)
查询 (x) 数的排名(排名定义为比当前数小的数的个数 (+1) )
查询排名为 (x) 的数
求 (x) 的前驱(前驱定义为小于 (x),且最大的数)
求 (x) 的后继(后继定义为大于 (x),且最小的数)
输入格式
第一行为 (n),表示操作的个数,下面 (n) 行每行有两个数 ( ext{opt}) 和 (x),( ext{opt}) 表示操作的序号( (1 leq ext{opt} leq 6) )
输出格式
对于操作 (3,4,5,6) 每行输出一个数,表示对应答案
Splay
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5,INF=1<<30;
inline int read(){
int x=0,f=1; char c=getchar();
while(c<'0'||c>'9'){ if(c=='-')f=-1; c=getchar(); }
while('0'<=c&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
return x*f;
}
int ch[N][2],par[N],val[N],cnt[N],size[N],ncnt,root;
inline bool chk(int x){ return ch[par[x]][1]==x; }
inline void pushup(int x){ size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x]; }
inline void rotate(int x){
int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1];
ch[z][chk(y)]=x,par[x]=z;
ch[y][k]=w,par[w]=y;
ch[x][k^1]=y,par[y]=x;
pushup(y),pushup(x);
}
inline void splay(int x,int goal=0){
while(par[x]!=goal){
int y=par[x],z=par[y];
if(z!=goal)chk(x)==chk(y)?rotate(y):rotate(x);
rotate(x);
}
if(!goal)root=x;
}
inline void insert(int x){
int p=root,cur=0;
while(p&&val[p]!=x)cur=p,p=ch[p][x>val[p]];
if(p)cnt[p]++;
else {
p=++ncnt;
if(cur)ch[cur][x>val[cur]]=p;
ch[p][0]=ch[p][1]=0;
par[p]=cur,val[p]=x;
cnt[p]=size[p]=1;
}
splay(p);
}
inline void find(int x){
int p=root;
while(ch[p][x>val[p]]&&x!=val[p])p=ch[p][x>val[p]];
splay(p);
}
inline int kth(int k){
int p=root;
while(1){
if(ch[p][0]&&k<=size[ch[p][0]])p=ch[p][0];
else if(k>size[ch[p][0]]+cnt[p]){
k-=size[ch[p][0]]+cnt[p];
p=ch[p][1];
}else return p;
}
}
inline int pre(int x){
find(x);
if(val[root]<x)return root;
int p=ch[root][0];
while(ch[p][1])p=ch[p][1];
return p;
}
inline int succ(int x){
find(x);
if(val[root]>x)return root;
int p=ch[root][1];
while(ch[p][0])p=ch[p][0];
return p;
}
inline void remove(int x){
int last=pre(x),nxt=succ(x);
splay(last),splay(nxt,last);
int p=ch[nxt][0];
if(cnt[p]>1)cnt[p]--,splay(p);
else ch[nxt][0]=0;
}
int n,op,x;
signed main(){
n=read();
insert(INF);
insert(-INF);
while(n--){
op=read(),x=read();
switch (op){
case 1: insert(x); break;
case 2: remove(x); break;
case 3: find(x); printf("%d
",size[ch[root][0]]); break;
case 4: printf("%d
",val[kth(x+1)]); break;
case 5: printf("%d
",val[pre(x)]); break;
case 6: printf("%d
",val[succ(x)]); break;
}
}
}
Treap
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int SIZE=2e5+10;
struct Treap{
int l,r;
int val,dat;
int cnt,size;
}a[SIZE];
int tot,root,n,INF=0x7fffffff;
inline int New(int val){
a[++tot].val=val;
a[tot].dat=rand();
a[tot].cnt=a[tot].size=1;
return tot;
}
inline void Update(int p){
a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
}
inline void Build(){
New(-INF),New(INF);
root=1,a[1].r=2;
Update(root);
}
int GetRankByVal(int p,int val){
if(p==0)return 0;
if(val==a[p].val)return a[a[p].l].size+1;
if(val<a[p].val)return GetRankByVal(a[p].l,val);
return GetRankByVal(a[p].r,val)+a[a[p].l].size+a[p].cnt;
}
int GetValByRank(int p,int rank){
if(p==0)return INF;
if(a[a[p].l].size>=rank)return GetValByRank(a[p].l,rank);
if(a[a[p].l].size+a[p].cnt>=rank)return a[p].val;
return GetValByRank(a[p].r,rank-a[a[p].l].size-a[p].cnt);
}
inline void zig(int &p){
int q=a[p].l;
a[p].l=a[q].r,a[q].r=p,p=q;
Update(a[p].r),Update(p);
}
inline void zag(int &p){
int q=a[p].r;
a[p].r=a[q].l,a[q].l=p,p=q;
Update(a[p].l),Update(p);
}
inline void Insert(int &p,int val){
if(p==0){
p=New(val);
return;
}
if(val==a[p].val){
a[p].cnt++,Update(p);
return;
}
if(val<a[p].val){
Insert(a[p].l,val);
if(a[p].dat<a[a[p].l].dat)zig(p);
}else{
Insert(a[p].r,val);
if(a[p].dat<a[a[p].r].dat)zag(p);
}
Update(p);
}
inline int GetPre(int val){
int ans=1,p=root;
while(p){
if(val==a[p].val){
if(a[p].l){
p=a[p].l;
while(a[p].r)p=a[p].r;
ans=p;
}
break;
}
if(a[p].val<val&&a[p].val>a[ans].val)ans=p;
p=val<a[p].val?a[p].l:a[p].r;
}
return a[ans].val;
}
inline int GetNext(int val){
int ans=2,p=root;
while(p){
if(val==a[p].val){
if(a[p].r){
p=a[p].r;
while(a[p].l)p=a[p].l;
ans=p;
}
break;
}
if(a[p].val>val&&a[p].val<a[ans].val)ans=p;
p=val<a[p].val?a[p].l:a[p].r;
}
return a[ans].val;
}
void Remove(int &p,int val){
if(p==0)return;
if(val==a[p].val){
if(a[p].cnt>1){
a[p].cnt--,Update(p);
return;
}
if(a[p].l||a[p].r){
if(a[p].r==0||a[a[p].l].dat>a[a[p].r].dat)zig(p),Remove(a[p].r,val);
else zag(p),Remove(a[p].l,val);
Update(p);
}
else p=0;
return;
}
val<a[p].val?Remove(a[p].l,val):Remove(a[p].r,val);
Update(p);
}
signed main(){
srand(time(0));
Build();
cin>>n;
while(n--){
int opt,x;
scanf("%lld%lld",&opt,&x);
switch(opt){
case 1:
Insert(root,x);
break;
case 2:
Remove(root,x);
break;
case 3:
printf("%lld
",GetRankByVal(root,x)-1);
break;
case 4:
printf("%lld
",GetValByRank(root,x+1));
break;
case 5:
printf("%lld
",GetPre(x));
break;
case 6:
printf("%lld
",GetNext(x));
break;
}
}
}