[HNOI2004]宠物收养场 题解 set

题目链接:https://www.luogu.com.cn/problem/P2286

题目大意:
\(N(N \le 80000)\) 只宠物或领养者依次来到宠物收养场,他们都有一个特征值。

当有一只宠物进入收养场时,如果存在等待的领养者,会从领养者中挑选和宠物特征值最接近的领养者匹配(然后离开收养场);否则,宠物等待。

当有一个领养者进入收养场时,如果存在等待的宠物,会从宠物中挑选和领养者特征值最接近的宠物匹配(然后离开收养场);否则,领养者等待。

每次匹配,答案都会加上匹配的宠物和领养者的差的绝对值,求答案。

解题思路:

首先这种边界性问题考虑用二分解决。
但是数据是动态的(动态插入和删除),所以考虑用集合(set)来维护数据,然后在set上进行二分。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 80080, MOD = 1000000;
set<int> pets, owners;
int n, ans, op, a;
void solve(set<int> &st, int a) {
    if (st.size() == 1) {
        ans = (ans + abs(a - (*st.begin()))) % MOD;
        st.clear();
    }
    else {
        set<int>::iterator r = st.lower_bound(a);
        if (r == st.begin()) {
            ans = (ans + abs(a - (*st.begin()))) % MOD;
            st.erase(r);
        }
        else {
            set<int>::iterator l = --st.lower_bound(a);
            if (r == st.end() || abs(a - *l) <= abs(a - *r)) {
                ans = (ans + abs(a - (*l))) % MOD;
                st.erase(l);
            }
            else {
                ans = (ans + abs(a - (*r))) % MOD;
                st.erase(r);
            }
        }
    }
}
int main() {
    scanf("%d", &n);
    while (n --) {
        scanf("%d%d", &op, &a);
        if (op == 0) {
            if (owners.size() == 0) pets.insert(a);
            else solve(owners, a);
        }
        else {
            if (pets.size() == 0) owners.insert(a);
            else solve(pets, a);
        }
    }
    printf("%d\n", ans);
    return 0;
}
posted @ 2020-01-31 20:59  quanjun  阅读(187)  评论(0编辑  收藏  举报