问题描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
输入格式:
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
题目来源 http://www.lydsy.com/JudgeOnline/problem.php?id=3224
splay笔记 》》http://blog.csdn.net/ctsas/article/details/70524330
(将理论实现真的好不容易,这代码耗费了我好几天时间 QAQ)
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
node *left,*right;
node *parent;
int key;
int size; //子树大小
int cnt; //该节点key重数
node(){
left=right=parent=NULL;
size=cnt=0;
}
}*root=NULL;
void update(node *x){
if(!x) return ;
x->size=x->cnt;
if(x->left) x->size+=x->left->size;
if(x->right)x->size+=x->right->size;
}
void zig(node *x){
node *y=x->parent;
if(y->parent){
if(y->parent->left==y)
y->parent->left=x;
else
y->parent->right=x;
}
x->parent=y->parent;
y->parent=x;
y->left=x->right; if(y->left) y->left->parent=y;
x->right=y;
if(!x->parent) root=x;
update(y);update(x);
}
void zag(node *x){
node *y=x->parent;
if(y->parent){
if(y->parent->left==y)
y->parent->left=x;
else
y->parent->right=x;
}
x->parent=y->parent;
y->parent=x;
y->right=x->left; if(y->right) y->right->parent=y;
x->left=y;
if(!x->parent) root=x;
update(y);update(x);
}
void splay(node *x){
while(x&&x->parent){
if(!x->parent->parent){
if(x->parent->left==x)
zig(x);
else
zag(x);
}
else if(x->parent->left==x&&x->parent->parent->left==x->parent){
zig(x->parent);//zig(x);注意啊 写成zig(x)就失去splay的意义了
zig(x);
}
else if(x->parent->right==x&&x->parent->parent->right==x->parent){
zag(x->parent);//zag(x);
zag(x);
}
else if(x->parent->left==x&&x->parent->parent->right==x->parent){
zig(x);
zag(x);
}
else{
zag(x);
zig(x);
}
}
}
node* subtree_minimum(node *u){
while(u->left) u=u->left;
return u;
}
node* subtree_maximum(node *u){
while(u->right) u=u->right;
return u;
}
bool cmop(int x,int y){
return x<y;
}
node *find(int key){
node *z=root;
while(z){
if(cmop(z->key , key)) z=z->right;
else if(cmop(key , z->key)) z=z->left;
else {
splay(z);
return z;
}
}
return NULL;
}
int Rank(int key){
int ans=0;
node *z=root;
while(z){
if(key<z->key) z=z->left;
else{
ans+=z->left?z->left->size:0;
if(key==z->key){
splay(z);
return ans+1;
}
ans+=z->cnt;
z=z->right;
}
}
return ans+1;
}
node *select(int R){
node *z=root,*p;
while(z){
p=z;
if(z->left&&R<=z->left->size) z=z->left;
else{
int r=(z->left?z->left->size:0)+z->cnt;
if(R<=r) break;
R-=r;
z=z->right;
}
}
splay(p);
return p;
}
void insert(int key){
node *z=root;
node *p=find(key);
if(p){
p->cnt++;
p->size++;
return ;
}
while(z){
p=z;
if(cmop(z->key , key)) z=z->right;
else z=z->left;
}
z=new node;
z->key=key;
z->parent=p;
z->size=1;
z->cnt=1;
if(!p) root=z;
else {
if(cmop(p->key , z->key)) p->right=z;
else p->left=z;
update(p);
splay(z);
}
}
//下面两个 pre 和 suc 貌似可以利用搜索顺序进行逻辑优化
node *pre(int key){
node *z=root,*p=NULL;
while(z){
if(key>z->key&&(p==NULL||p&&z->key>p->key)) p=z;
if(key>z->key) z=z->right;
else z=z->left;
}
splay(p);
return p;
}
node *suc(int key){
node *z=root,*p=NULL;
while(z){
if(key<z->key&&(p==NULL||p&&z->key<p->key)) p=z;
if(key>=z->key) z=z->right;
else z=z->left;
}
splay(p);
return p;
}
void erase(int key){
node *z=find(key);
if(!z) return ;
if(z->cnt>1){
z->cnt--;
z->size--;
return ;
}
if(!z->left&&!z->right){
delete z;
root=NULL;
}
else if(!z->left){
root=z->right;
z->right->parent=NULL;
delete z;
update(root);
}
else if(!z->right){
root=z->left;
z->left->parent=NULL;
delete z;
update(root);
}
else {
node *y=subtree_minimum(z->right);
z->left->parent=y;
y->left=z->left;
root=z->right;
z->right->parent=NULL;
delete z;
update(y);
update(root);
splay(y);
}
}
int main()
{
// freopen("C:\\Users\\chutzpah\\Desktop\\ot.txt","r",stdin);
// freopen("C:\\Users\\chutzpah\\Desktop\\2.txt","w",stdout);
int n;scanf("%d",&n);
while(n--){
int op,c,ans,r,l;node *t;
scanf("%d%d",&op,&c);
// if(op>2) printf("%d %5d| ",op,c);
switch(op){
case 1: insert(c);break;
case 2: erase(c);break;
case 3: printf("%d\n",Rank(c));break;
case 4: printf("%d\n",select(c)->key); break;
case 5: printf("%d\n",pre(c)->key); break;
case 6: printf("%d\n",suc(c)->key); break;
}
}
return 0;
}