BZOJ 1208, 宠物收养所

14 篇文章 0 订阅
2 篇文章 0 订阅

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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值