Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=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<=100000
2.每个数的数据范围:[-2e9,2e9]
Source
平衡树
今日新学一数据结构曰:treap,其原理就是当数据随机输入时,二叉平衡树的均摊复杂度是(logn)的,所以就有了以下操作,我们给每个树节点都随机附一个fix值,按照fix建立小根堆,同时满足二叉搜索树的性质,每次插入时先将其插到二叉树的位置,然后rand一个fix后调整:如果他比他爸爸fix小就rotate他。
每次删除时可作以下判断:如果说他的儿子不满,就把他的儿子来替换他(没有就直接删了)否则比较两个儿子的fix值把fix值小的旋上来,一直旋直到他的儿子不满直接操作。
今天因为不能够直接splay,还学了对非根节点求前驱、后缀、求他的排名的操作,得好好看。
#include<bits/stdc++.h>
using namespace std;
#define N 2000001
int ch[N][2],val[N],fix[N],fa[N],S[N],num[N];
int sz,n,opt,k,root;
void pushup(int x){S[0]=0;S[x]=S[ch[x][1]]+S[ch[x][0]]+num[x];return;}
bool gets(int x)
{
return (ch[fa[x]][1]==x);
}
int find(int x)
{
int p=root;
while(val[p]!=x)
{
if(val[p]<x) {if(ch[p][1]) p=ch[p][1];else return p;}
else{if(ch[p][0]) p=ch[p][0];else return p;}
}
return p;
}
void rotate(int x)
{
if(!x) return;bool d=gets(x);
int F=fa[x];int GF=fa[F];
if(GF) ch[GF][gets(F)]=x;
fa[x]=GF;fa[F]=x;fa[ch[x][!d]]=F;ch[F][d]=ch[x][!d];ch[x][!d]=F;
pushup(F);pushup(x);
if(fa[x]==0) root=x;
}
void change(int no)
{while(fa[no]&&fix[no]<fix[fa[no]]) rotate(no); }
void insert(int x)
{
if(!root){root=++sz;val[sz]=x;fix[sz]=rand();fa[sz]=0;num[sz]=1;pushup(sz);return;}
int kk=find(x);
if(val[kk]!=x)
{
fix[++sz]=rand();val[sz]=x;fa[sz]=kk;S[sz]=1;num[sz]=1;
if(x>val[kk]){ch[kk][1]=sz;}else ch[kk][0]=sz;
for(int i=sz;i;i=fa[i])pushup(i);
change(sz);
}
else
{
num[kk]++;for(int i=kk;i;i=fa[i])pushup(i);
}
}
int getn(int no)
{
return fix[ch[no][1]]<=fix[ch[no][0]];
}
void del(int x)
{
int no=find(x);
num[no]--;
for(int i=no;i;i=fa[i]) pushup(i);//必要的话
if(num[no]==0)
{
while(ch[no][1]*ch[no][0])
{
int ll=getn(no);
rotate(ch[no][ll]);
}
int tt=ch[no][1]+ch[no][0];
ch[fa[no]][gets(no)]=tt;fa[tt]=fa[no];fa[no]=0;
if(fa[tt]==0) root=tt;
for(int i=tt;i;i=fa[i])pushup(i);
}
return;
}
int qrank(int x,int p)
{
if(p==0) return 0;
if(val[p]==x) return S[ch[p][0]]+1;
if(val[p]>x) return qrank(x,ch[p][0]);
return S[ch[p][0]]+num[p]+qrank(x,ch[p][1]);
}
int element(int k)
{
int r=root;
if(k>S[root]) return 0;
while(1)
{
if(S[ch[r][0]]<k&&S[ch[r][0]]+num[r]>=k) return val[r];
if(S[ch[r][0]]>=k) r=ch[r][0];
else if(S[ch[r][1]]) {k-=num[r]+S[ch[r][0]];r=ch[r][1];}
}
}
int succ(int x){int p=root;int ans=0;while(p){if(val[p]<x) ans=max(ans,val[p]),p=ch[p][1];else p=ch[p][0];}return ans;}
int pred(int x){int p=root;int ans=2e9+1e8;while(p){if(val[p]>x) ans=min(ans,val[p]),p=ch[p][0];else p=ch[p][1];}return ans;}
int main()
{
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&opt,&k);
if(opt==1) insert(k);
if(opt==2) del(k);
if(opt==3) {printf("%d\n",qrank(k,root));}
if(opt==4) {printf("%d\n",element(k));}
if(opt==5) {insert(k);printf("%d\n",succ(k));del(k);}
if(opt==6) {insert(k);printf("%d\n",pred(k));del(k);}
}
}