欲望以提升热忱,毅力以磨平高山!|

XichenOC

园龄:1个月粉丝:4关注:0

2025-01-23 20:39阅读: 2评论: 0推荐: 0

P2286 [HNOI2004] 宠物收养场

P2286 [HNOI2004] 宠物收养场

题目翻译:

给定 \(n\) 次操作,每次操作会添加一个元素。并且维护一个集合,若当前添加的元素与集合中元素种类相同,则直接添加,若不相同这要将最终答案加上给元素与集合中元素的差的绝对值的最小值,并删除对应的集合中的元素。(特别注意:若有两个元素与添加元素的差相同,则删除较小的那个)

思路:

若要找到一个与添加元素最接近的元素,且可以随意删除添加,很容易想到平衡树。我们维护一个平衡树,在查询的时候直接找前驱和后继,求最小值然后,删除即可。对于两种不同种类的元素,我们只需要用一个变量 \(op\) 维护当前集合中的元素类型,并用 \(cnt\) 变量维护当前集合中元素个数,这样每次添加元素时,若 \(cnt=0\) 就给 \(op\) 赋值为当前元素类型,即可。

完整代码:

#include<bits/stdc++.h>
#define fa(x) tr[(x)].fa
#define lc(x) tr[(x)].s[0]
#define rc(x) tr[(x)].s[1]
using namespace std;
const int N=1e5+10;
const int P=1000000;
struct tree{
    int s[2],fa,siz,key;
    tree(){s[0]=s[1]=fa=siz=key=0;}
}tr[N];
int rt,idx;
void pushup(int x){
    tr[x].siz=tr[lc(x)].siz+tr[rc(x)].siz+1;
}
int newnode(int key){
    tr[++idx].key=key;
    tr[idx].siz=1;
    return idx;
}
int get(int x){
    return x==rc(fa(x));
}
void clear(int x){
    lc(x)=rc(x)=fa(x)=tr[x].siz=tr[x].key=0;
}
void rotate(int x){
    int y=fa(x),z=fa(y),c=get(x);
    if(tr[x].s[c^1])tr[tr[x].s[c^1]].fa=y;
    tr[y].s[c]=tr[x].s[c^1];
    tr[x].s[c^1]=y;
    fa(y)=x;
    fa(x)=z;
    if(z)tr[z].s[y==rc(z)]=x;
    pushup(y);
    pushup(x);
}
void splay(int x){
    for(int f=fa(x);f=fa(x),f;rotate(x)){
        if(fa(f))rotate(get(x)==get(x)?f:x);
    }
    rt=x;
}
void ins(int key){
    int now=rt,f=0;
    while(now){
        f=now;
        now=tr[now].s[key>tr[now].key];
    }
    now=newnode(key);
    tr[f].s[key>tr[f].key]=now;
    fa(now)=f;
    splay(now);
}
int pre(int key){
    int now=rt,f=0,ans=0;
    while(now){
        f=now;
        if(tr[now].key>key){
            now=lc(now);
        }
        else{
            ans=tr[now].key;
            now=rc(now);
        }
    }
    splay(f);
    return ans;
}
int nxt(int key){
    int now=rt,f=0,ans=0;
    while(now){
        f=now;
        if(tr[now].key<key){
            now=rc(now);
        }
        else{
            ans=tr[now].key;
            now=lc(now);
        }
    }
    splay(f);
    return ans;
}
void del(int key){
    int now=rt,f=0;
    while(now && key!=tr[now].key){
        f=now;
        now=tr[now].s[key>tr[now].key];
    }
    if(!now){
        splay(f);
        return;
    }
    splay(now);
    int cur=lc(now);
    if(!cur){
        rt=rc(now);
        fa(rt)=0;
        clear(now);
        return;
    }
    while(rc(cur)){
        cur=rc(cur);
    }
    fa(rc(now))=cur;
    rc(cur)=rc(now);
    fa(lc(now))=0;
    clear(now);
    pushup(cur);
    splay(cur);
}
int main(){
    ins(+214748364);
    ins(-214748364);
    int n;
    scanf("%d",&n);
    int op,w,now,ans=0,cnt=0;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&op,&w);
        if(cnt==0){
            now=op;
        }
        if(op==now){
            ins(w);
            cnt++;
        }
        else{
            int w1=pre(w),w2=nxt(w);
            //cout<<w1<<" "<<w2<<endl;
            if(abs(w-w1)<=abs(w-w2)){
                ans+=abs(w-w1);
                ans%=P;
                cnt--;
                del(w1);
            }
            else{
                ans+=abs(w-w2);
                ans%=P;
                cnt--;
                del(w2);
            }
        }
    }
    printf("%d",ans);
}

平衡树讲解

本文作者:XichenOC

本文链接:https://www.cnblogs.com/XichenOC/p/18688603

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XichenOC  阅读(2)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起