BZOJ 3224 普通平衡树
题目描述 Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
最开始所有元素都是0。
输入描述 Input Description
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出描述 Output Description
对于操作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
数据范围及提示 Data Size & Hint
n≤100000,-inf≤x≤inf
分析: 这里的每个操作都是基本操作,详见Splay学习小结
Code:
#include <bits/stdc++.h>
using namespace std;
#define maxn 100010
int ch[maxn][2],f[maxn],size[maxn],cnt[maxn],key[maxn];
int sz,root;
bool get(int x) {return ch[f[x]][1]==x;}
void clear(int x) {
ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
return ;
}
void update(int x) {
if(x) {
size[x]=cnt[x];
if(ch[x][0]) size[x]+=size[ch[x][0]];
if(ch[x][1]) size[x]+=size[ch[x][1]];
}
return ;
}
void rotate(int x) {
int old=f[x],oldf=f[old],whichx=get(x);
ch[old][whichx]=ch[x][whichx^1];
f[ch[old][whichx]]=old;
ch[x][whichx^1]=old;
f[old]=x;
f[x]=oldf;
if(oldf)
ch[oldf][ch[oldf][1]==old]=x;
update(old);
update(x);
return ;
}
void splay(int x) {
for(int fa;fa=f[x];rotate(x))
if(f[fa])
rotate(get(x)==get(fa)?fa:x);
root=x;
return ;
}
void insert(int x) {
if(root==0) {
sz++;
ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
return ;
}
int now=root,fa=0;
while(1) {
if(x==key[now]) {
cnt[now]++;
update(now);
update(fa);
splay(now);
break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==0) {
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=cnt[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
return ;
}
int find(int x) {
int now=root,ans=0;
while(1) {
if(x<key[now])
now=ch[now][0];
else {
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(x==key[now]) {
splay(now);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
}
}
int findx(int x) {
int now=root;
while(1) {
if(ch[now][0]&&x<=size[ch[now][0]])
now=ch[now][0];
else {
int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=tmp) return key[now];
x-=tmp;
now=ch[now][1];
}
}
}
int pre() {
int now=ch[root][0];
while(ch[now][1]) now=ch[now][1];
return now;
}
int next() {
int now=ch[root][1];
while(ch[now][0]) now=ch[now][0];
return now;
}
void del(int x) {
int whatever=find(x);
if(cnt[root]>1) {
cnt[root]--;
update(root);
return ;
}
if(!ch[root][0] && !ch[root][1]) {
clear(root);
root=0;
return ;
}
if(!ch[root][0]) {
int oldroot=root;
root=ch[root][1];
f[root]=0;
clear(oldroot);
return ;
}
else if(!ch[root][1]) {
int oldroot=root;
root=ch[root][0];
f[root]=0;
clear(oldroot);
return ;
}
int leftbig=pre(),oldroot=root;
splay(leftbig);
ch[root][1]=ch[oldroot][1];
f[ch[oldroot][1]]=root;
clear(oldroot);
update(root);
return ;
}
int main() {
int n,opt,x;
scanf("%d",&n);
for(int i=1;i<=n;++i) {
scanf("%d%d",&opt,&x);
switch(opt) {
case 1: {
insert(x);
break;
}
case 2: {
del(x);
break;
}
case 3: {
printf("%d\n",find(x));
break;
}
case 4: {
printf("%d\n",findx(x));
break;
}
case 5: {
insert(x);
printf("%d\n",key[pre()]);
del(x);
break;
}
case 6: {
insert(x);
printf("%d\n",key[next()]);
del(x);
break;
}
}
}
return 0;
}