Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求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
这个题目,标准的就是splay的一些基本操作,直接如下模拟
小细节要考虑好啊。。。记住,树里面存放的是下标
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAX = 100010;
const int INF = 0x7fffffff;
int ch[MAX][2],f[MAX],key[MAX];
int cnt[MAX],Size[MAX],mark[MAX];
//伸展树不需要额外的空间
int root,sz;
typedef long long ll;
inline int get(int x){
return ch[f[x]][1] == x;
}
inline void clean(int x){
ch[x][0] = ch[x][1] = f[x] = cnt[x] = key[x] = Size[x] = 0;
}
inline 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]];
}
}
inline void Rotate(int x){
int y = f[x],z = f[y];
int kind = get(x);
ch[y][kind] = ch[x][!kind];
f[ch[y][kind]] = y;
f[y] = x;ch[x][!kind] = y;
f[x] = z;
if(z) ch[z][ch[z][1] == y] = x;
update(y);update(x);
//这里y变成儿子了,所以先更新y
}
inline void Splay(int x){
//把x扭到根节点
for(int fa;(fa = f[x]);Rotate(x)){
if(f[fa]) Rotate((get(x)==get(fa))? fa:x);
}
root = x;
}
inline bool Insert(int x){
if(root == 0){
sz++;
Size[sz] = cnt[sz] = 1;
ch[sz][0] = ch[sz][1] = f[sz] = 0;
root = sz;key[sz] = x;
return true;
}
int now = root,fa = 0;
while(true){
if(key[now] == x){
cnt[now]++;
update(fa);
Splay(now);
return false;
}
fa = now;
now = ch[now][x > key[now]];
if(now == 0){
sz++;
Size[sz] = cnt[sz] = 1;
ch[sz][0] = ch[sz][1] = 0;
key[sz] = x;
f[sz] = fa;
ch[fa][x > key[fa]] = sz;
Splay(sz);
return true;
}
}
}
inline int QueryNumRank(int x){
int ans = 0,now = root;
while(true){
if(x < key[now])
now = ch[now][0];
else{
ans += ch[now][0]?Size[ch[now][0]]:0;
if(key[now] == x){
Splay(now);
return ans+1;
}
ans += cnt[now];
now = ch[now][1];
}
}
}
inline int QueryRankNum(int x){
int now = root;
while(true){
if(ch[now][0] && Size[ch[now][0]] >= x)
now = ch[now][0];
else{
int tmp = (ch[now][0]? Size[ch[now][0]]:0) + cnt[now];
if(tmp >= x){
return key[now];
}
x -= tmp;now = ch[now][1];
}
}
}
//注意这里查询,返回的是标号,不是key,因为在del中又用到这些操作了。
int QueryPre(){
int k = ch[root][0];
while(ch[k][1]) k = ch[k][1];
return k;
}
int QueryNex(){
int k = ch[root][1];
while(ch[k][0]) k = ch[k][0];
return k;
}
void del(int x){
QueryNumRank(x);//先把这个数扭到根节点
if(cnt[root] > 1) cnt[root]--;
else if(!ch[root][0] && !ch[root][1]){
clean(root);
root = 0;
}
else if(!ch[root][0]){
int tmp = root;
root = ch[root][1];
f[root] = 0;
clean(tmp);
}
else if(!ch[root][1]){
int tmp = root;
root = ch[root][0];
f[root] = 0;
clean(tmp);
}
else{
int t = QueryPre();
int tmp = root;
Splay(t);
ch[root][1] = ch[tmp][1];
f[ch[tmp][1]] = root;
clean(tmp);
update(root);
}
}
int main(void){
int N,x,op;
scanf("%d",&N);
for(int i=1;i<=N;++i){
scanf("%d%d",&op,&x);
if(op == 1) Insert(x);
else if(op == 2) del(x);
else if(op == 3) printf("%d\n",QueryNumRank(x));
else if(op == 4) printf("%d\n",QueryRankNum(x));
else if(op == 5){
Insert(x);
printf("%d\n",key[QueryPre()]);
del(x);
}
else{
Insert(x);
printf("%d\n",key[QueryNex()]);
del(x);
}
}
return 0;
}