Problem
Mean
编写一个支持插入、删除元素,查询数列中最接近某值的元素的数据结构。
保证没有重复元素存在出现在树中。
Analysis
Treap和Splay都可做。
Splay苦手选择Treap,然而写得奇丑无比。
查询最接近某值的元素可以将该值插入树中查询前驱与后继,后比较。查询完以后再删掉。
Code
#include<cstdio>
#include<cstdlib>
const int MOD=1000000;
int n,a,b,p,ans;
int abs(int x){return x<0?-x:x;}
struct Node{
Node* ch[2];
int r,v,s;
int cmp(int x) const {
if(x==v) return -1;
return x>v;
}
void maintain(){
s=1;
if(ch[0]!=NULL) s+=ch[0]->s;
if(ch[1]!=NULL) s+=ch[1]->s;
}
};
void rotate(Node* &o,int d){
Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
o->maintain();k->maintain();o=k;
}
void insert(Node* &o,int x){
if(o==NULL){o=new Node();o->ch[0]=o->ch[1]=NULL;o->v=x,o->r=rand();}
else{
int d=o->cmp(x);
insert(o->ch[d],x);
if(o->ch[d]->r>o->r) rotate(o,d^1);
}
o->maintain();
}
void remove(Node* &o,int x){
int d=o->cmp(x);
if(d==-1){
if(o->ch[0]==NULL) o=o->ch[1];
else if(o->ch[1]==NULL) o=o->ch[0];
else{
int d2=o->ch[0]->r>o->ch[1]->r;
rotate(o,d2);
remove(o->ch[d2],x);
}
}else remove(o->ch[d],x);
if(o!=NULL) o->maintain();
}
int find(Node* o,int x){
while(o!=NULL){
int d=o->cmp(x);
if(d==-1) return 1;
else o=o->ch[d];
}
return 0;
}
int rank(Node* o,int x){
int d=o->cmp(x),s=o->ch[0]==NULL?0:o->ch[0]->s;
if(d==-1) return s+1;
if(d==0) return rank(o->ch[0],x);
return s+1+rank(o->ch[1],x);
}
int kth(Node* o,int x){
int s=o->ch[0]==NULL?0:o->ch[0]->s;
if(s+1==x) return o->v;
if(s>=x) return kth(o->ch[0],x);
return kth(o->ch[1],x-s-1);
}
int main(){
Node* o=NULL;
scanf("%d",&n);
while(n--){
scanf("%d%d",&a,&b);
if(o==NULL){p=a;insert(o,b);}
else if(a==p) insert(o,b);
else{
if(find(o,b)) remove(o,b);
else if(o->s==1) (ans+=abs(o->v-b))%=MOD,remove(o,o->v);
else{
insert(o,b);
int f=rank(o,b),y,x;
if(f==1) y=kth(o,2),(ans+=abs(y-b))%=MOD,remove(o,y);
else if(f==o->s) x=kth(o,f-1),(ans+=abs(x-b))%=MOD,remove(o,x);
else{
x=kth(o,f-1),y=kth(o,f+1);
if(abs(x-b)<=abs(y-b)) (ans+=abs(x-b))%=MOD,remove(o,x);
else (ans+=abs(y-b))%=MOD,remove(o,y);
}
remove(o,b);
}
}
}
printf("%d",ans);
}