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.每个数的数据范围:[-1e7,1e7]
Source
平衡树
终于把splay艹出来了!!!!!!!!!!!!!
不过还是抄的viv&&小绿的模板 _(: 3
自己悟的splay总是RE之类的……没看书就用指针就是我这种下场……得抽空补一下语言
基础了…………
说一下基本操作:
插入:按普通平衡树那样插入,插入完了splay到根。
删除:splay到根,如果只有一个儿子,则改一下根的指针到那个儿子即可。若有俩儿子,则把这个数的前驱splay到根的左儿子位置上,然后改一下根的指针指向前驱即可。
剩余四个操作看代码就懂了…
splay(p,rt) :把p节点转到父节点为rt的位置上。
rotate(p):把p节点转到父节点的位置上。
附上代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int SZ = 1000010;
const int INF = 1000000010;
struct node{
node *ch[2],*f;
int sz,cnt,v;
void maintain()
{
sz = cnt + ch[0] -> sz + ch[1] -> sz;
}
int cmp(int x)
{
if(x == v) return -1;
return x < v ? 0 : 1;
}
int dir()
{
return f -> ch[1] == this;
}
void setc(node *x,int d)
{
(ch[d] = x) -> f = this;
}
}T[SZ], *root, *null;
int Tcnt = 0;
node* newnode(int x,node *f)
{
node *k = T + (++ Tcnt);
k -> v = x;
k -> ch[0] = k -> ch[1] = null;
k -> sz = k -> cnt = 1;
k -> f = f;
return k;
}
void rotate(node *p)
{
node *fa = p -> f;
int d = p -> dir();
fa -> f -> setc(p,fa -> dir());
fa -> setc(p -> ch[d ^ 1],d); fa -> maintain();
p -> setc(fa,d ^ 1); p -> maintain();
if(fa == root) root = p;
}
void splay(node *p,node *rt = null)
{
while(p -> f != rt)
{
if(p -> f -> f == rt) rotate(p);
else
{
if(p -> dir() == p -> f -> dir())
rotate(p -> f),rotate(p);
else
rotate(p),rotate(p);
}
}
}
void insert(node *p,int x)
{
if(root == null) { root = newnode(x,null); return ; }
while(p != null)
{
p -> sz ++;
int d = p -> cmp(x);
if(d == -1) { p -> cnt ++; break; }
if(p -> ch[d] == null)
{
p -> ch[d] = newnode(x,p);
p = p -> ch[d];
break;
}
p = p -> ch[d];
}
splay(p);
}
void erase(node *p,int x)
{
while(p != null)
{
p -> sz --;
int d = p -> cmp(x);
if(d == -1) { p -> cnt --; break; }
p = p -> ch[d];
}
if(p -> cnt) return ;
splay(p);
if(p -> ch[0] == null) { root = p -> ch[1]; root -> f = null; return ; }
if(p -> ch[1] == null) { root = p -> ch[0]; root -> f = null; return ; }
p = p -> ch[0];
while(p -> ch[1] != null) p = p -> ch[1];
splay(p,root);
p -> ch[1] = root -> ch[1]; p -> ch[1] -> f = p;
p -> f = null; p -> maintain();
root = p;
}
int ask_rank(node *p,int x)
{
int ans = 0;
while(p != null)
{
int d = p -> cmp(x);
if(d == -1) return ans + p -> ch[0] -> sz + 1;
if(d == 1) ans += p -> ch[0] -> sz + p -> cnt;
p = p -> ch[d];
}
return -1;
}
int ask_num(node *p,int k)
{
while(p != null)
{
int l = p -> ch[0] -> sz + 1;
int r = p -> ch[0] -> sz + p -> cnt;
if(l <= k && k <= r) return p -> v;
if(k > r) k -= r,p = p -> ch[1];
else p = p -> ch[0];
}
}
int ask_pre(node *p,int x)
{
int ans = 0;
while(p != null)
{
if(p -> v < x)
ans = p -> v,p = p -> ch[1];
else
p = p -> ch[0];
}
return ans;
}
int ask_suf(node *p,int x)
{
int ans = 0;
while(p != null)
{
if(p -> v > x)
ans = p -> v,p = p -> ch[0];
else
p = p -> ch[1];
}
return ans;
}
void init()
{
null = newnode(-INF,null);
null -> sz = null -> cnt = 0;
root = null;
}
int main()
{
init();
int n;
scanf("%d",&n);
while(n --)
{
int opt,x;
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:
insert(root,x);
break;
case 2:
erase(root,x);
break;
case 3:
printf("%d\n",ask_rank(root,x));
break;
case 4:
printf("%d\n",ask_num(root,x));
break;
case 5:
printf("%d\n",ask_pre(root,x));
break;
case 6:
printf("%d\n",ask_suf(root,x));
break;
}
}
return 0;
}