描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
插入x数
删除x数(若有多个相同的数,因只删除一个)
查询x数的排名(若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数)
求x的后继(后继定义为大于x,且最小的数)
输入
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出
对于操作3,4,5,6每行输出一个数,表示对应答案
样例输入 [复制]
8
1 10
1 20
1 30
3 20
4 2
2 10
5 25
6 -1
样例输出 [复制]
2
20
20
20
数据规模:
n<=100000 所有数字均在-10^7 到 10 ^7内
思路:
平衡树模板,可以用非旋treap写
对于相同的数,处理的方式有很多种。这里多维护了两个数组
sam :当前权值下总数
alsam :当前子树总数(记重)
siz:当前子树总数(不记重)
3,4,询问单独写函数
PS:
其实也可以直接把相同的点加在树中,只有找到当前权值的点的时候,这同一权值的一部分才会被拆成两部分。所以 相等的时候 也向左子树走即可。
(这个代码写的有点丑。。)
其他的就是常规操作了
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define fi first
#define se second
#define in red()
inline int red()
{
int data=0;int w=1; char ch=0;
ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
const int maxn=3e5+10;
typedef pair<int,int> T;
int val[maxn],rd[maxn],son[maxn][2],sam[maxn],siz[maxn],cnt=0,root=0,alsam[maxn];
inline int push(int v){val[++cnt]=v;rd[cnt]=rand();siz[cnt]=sam[cnt]=alsam[cnt]=1;return cnt;}
inline void pushup(int k){siz[k]=siz[son[k][0]]+siz[son[k][1]]+1;alsam[k]=alsam[son[k][0]]+alsam[son[k][1]]+sam[k];}
inline int merge(int a,int b){
if(!a||!b)return a+b;
// if(val[a]>val[b])swap(a,b);
if(rd[b]<rd[a]){
son[a][1]=merge(son[a][1],b);pushup(a);return a;
}
son[b][0]=merge(a,son[b][0]);pushup(b);return b;
}
inline int rank(int p,int v){
if(!p)return 0;
if(val[p]<=v){
return rank(son[p][1],v)+siz[son[p][0]]+1;
}
return rank(son[p][0],v);
}
bool ff=1;
inline int find(int p,int v){
// pf("p:%d val[p]: %d v:%d\n",p,val[p],v);
if(!p)return 0;
if(val[p]==v){
//pf("succeed , v:%d\n",v);
ff=0;return alsam[son[p][0]]+1;
}
if(val[p]<v)return find(son[p][1],v)+alsam[son[p][0]]+sam[p];
return find(son[p][0],v);
}
inline int find2(int p,int k){
if(!p)return 0;
if(k<=alsam[son[p][0]]){
return find2(son[p][0],k);
}
k-=(alsam[son[p][0]]+sam[p]);
if(k<=0)return val[p];
return find2(son[p][1],k);
}
inline T split(int p,int k){
if(!p)return make_pair(0,0);
T ans,tmp;
if(k<=siz[son[p][0]]){
tmp=split(son[p][0],k);
son[p][0]=tmp.se;pushup(p);
ans.fi=tmp.fi;ans.se=p;
return ans;
}
tmp=split(son[p][1],k-siz[son[p][0]]-1);
son[p][1]=tmp.fi;pushup(p);
ans.fi=p;ans.se=tmp.se;
return ans;
}
inline void op1(int v,bool f){
int k=rank(root,v);
T t=split(root,k);T l=split(t.fi,k-1);
if(f==0){
if(val[l.se]==v){
//pf("f=0,val=v,val: %d\n",val[l.se]);
++sam[l.se];++alsam[l.se];
root=merge(merge(l.fi,l.se),t.se);
}
else{
//pf("f=0,fail;\n");
int k1=push(v);
root=merge(merge(merge(l.fi,l.se),k1),t.se);
}
}
else{
if(val[l.se]==v){
--sam[l.se];--alsam[l.se];
if(sam[l.se]<1){
root=merge(l.fi,t.se);
}
else{
root=merge(merge(l.fi,l.se),t.se);
}
}
}
}
inline int ask(int v,bool f){
int k=rank(root,v);
T t=split(root,k);T l=split(t.fi,k-1);
int ret;
if(f==0){
if(val[l.se]<v)ret=val[l.se];
else{
T ll=split(l.fi,k-2);
ret= val[ll.se];
l.fi=merge(ll.fi,ll.se);
}
}
else{
T mid=split(t.se,1);
ret=val[mid.fi];
t.se=merge(mid.fi,mid.se);
}
root=merge(merge(l.fi,l.se),t.se);
return ret;
}
void print(int p){
if(son[p][0])print(son[p][0]);
pf("%d ",val[p]);
if(son[p][1])print(son[p][1]);
}
signed main(){
//freopen("data.in","r",stdin);
int n;//sf("%d",&n);
n=in;
while(n--){
int f,v;f=in;v=in;
if(f==1)op1(v,0);
if(f==2)op1(v,1);
if(f==3){ff=1;int ans=find(root,v);pf("%d\n",ans+ff);}
if(f==4){pf("%d\n",find2(root,v));}
if(f==5)pf("%d\n",ask(v,0));
if(f==6)pf("%d\n",ask(v,1));
}
return 0;
}