BZOJ#1208[HNOI2004]宠物收养场

[HNOI2004]宠物收养场

image

思路:

使用两个multiset维护找到离当前的主人/宠物的最近的位置,删掉,亦可以使用平衡树

代码:

STL 写法
#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'


void solve(int Case) {
    multiset<int> a, b;
    int n;
    cin >> n;
    int res = 0;
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        if (x) {
            b.insert(y);
        } else {
            a.insert(y);
        }
        while (a.size() >= b.size() and b.size()) {
            auto it = b.begin();
            auto t = a.lower_bound(*it);
            int d1 = 1e9, d2 = 1e9;
            if (t != a.end()) {
                d1 = abs(*t - *it);
            }
            auto t1 = a.lower_bound(*it);
            if (t1 != a.begin()) {
                t1--;
                d2 = abs(*t1 - *it);
            }
            if (d1 < d2) {
                b.erase(it);
                a.erase(t);
                res += d1;
            } else {
                b.erase(it);
                a.erase(t1);
                res += d2;
            }
        }
        while (b.size() >= a.size() and a.size()) {
            auto it = a.begin();
            auto t = b.lower_bound(*it);
            int d1 = 1e9, d2 = 1e9;
            if (t != b.end()) {
                d1 = abs(*t - *it);
            }
            auto t1 = b.lower_bound(*it);
            if (t1 != b.begin()) {
                t1--;
                d2 = abs(*t1 - *it);
            }
            if (d1 < d2) {
                a.erase(it);
                b.erase(t);
                res += d1;
            } else {
                a.erase(it);
                b.erase(t1);
                res += d2;
            }
        }
        res %= 1000000;
        //cout<<res<<nline;
    }
    cout << res << nline;
}
signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
//   cin >> _; for (Case = 1; Case <= _; Case++)
    solve(Case);

    return 0;
}
平衡树写法
const int N = 200010, INF = 1e10;
struct T {
    int l, r, sz, cnt, key, val;
} tr[N << 1];//两颗平衡树
int idx , root1, root2, idx1 = N;
void pushup(int p) {
    tr[p].sz = tr[tr[p].l].sz + tr[tr[p].r].sz + tr[p].cnt;
}
int get_node(int key) {
    tr[++idx].key = key;
    tr[idx].sz = tr[idx].cnt = 1;
    tr[idx].val = rand();
    return idx;
}
int get_node1(int key) {
    tr[++idx1].key = key;
    tr[idx1].sz = tr[idx1].cnt = 1;
    tr[idx1].val = rand();
    return idx1;
}
void build() {
    get_node(-INF), get_node(INF);
    root1 = 1; tr[1].r = 2;
    pushup(root1);
    root2 = get_node1(-INF);
    int  t = get_node1(INF);
    tr[root2].r = t;
    pushup(root2);
}
//右旋
void zig(int &p) {
    int q = tr[p].l;
    tr[p].l = tr[q].r;
    tr[q].r = p;
    p = q;
    pushup(tr[p].r);
    pushup(p);
}
void zag(int &p) {
    int q = tr[p].r;
    tr[p].r = tr[q].l;
    tr[q].l = p;
    p = q;
    pushup(tr[p].l);
    pushup(p);
}
void insert(int &p, int key, int t) {
    if (!p) {
        if (!t) p = get_node(key);
        else p = get_node1(key);
    }
    else if (tr[p].key == key) tr[p].cnt++;
    else if (key < tr[p].key) {
        insert(tr[p].l, key, t);
        if (tr[tr[p].l].val > tr[p].val) {//调整堆的结构
            zig(p);
        }
    } else {
        insert(tr[p].r, key, t);
        if (tr[tr[p].r].val > tr[p].val) {
            zag(p);
        }

    }
    pushup(p);
}
void remove(int &p, int key) {
    if (!p) return;
    if (tr[p].key == key) {
        if (tr[p].cnt > 1) tr[p].cnt--;
        else if (tr[p].l or tr[p].r) { //有子树
            if (!tr[p].r or tr[tr[p].l].val > tr[tr[p].r].val) { //左子树val大于右子树
                zig(p);//右旋
                remove(tr[p].r, key);
            } else { //右子树val大于左子树
                zag(p);
                remove(tr[p].l, key);

            }
        } else { //没有子树。
            p = 0;
        }

    }
    else if (key < tr[p].key) remove(tr[p].l, key);
    else remove(tr[p].r, key);
    pushup(p);
}
int get_prev(int p, int key) {
    if (!p) return -INF;
    if (key == tr[p].key and tr[p].cnt>1) return key;
    if (key <= tr[p].key) {
        return get_prev(tr[p].l, key);
    }
    return max(tr[p].key, get_prev(tr[p].r, key));
}
int get_next(int p, int key) {
    if (!p) return INF;
    if (key == tr[p].key and tr[p].cnt>1) return key;
    if (key > tr[p].key) {
        return get_next(tr[p].r, key);
    } else return min(tr[p].key, get_next(tr[p].l, key));
}
int sza, szb;
void travel(int p){
    if(!p) return;
    travel(tr[p].l);
    cout<<tr[p].key<<nline;
    travel(tr[p].r);

}
void solve(int Case) {
    build();
    int n;
    cin >> n;
    int res = 0;
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        if (x) {
            insert(root1, y, 0);
            sza++;
        } else {
            insert(root2, y, 1);
            szb++;
        }
        while (sza <= szb and sza) {
            auto t = get_next(root1,-INF+1);
            auto left = get_prev(root2, t);
            auto right = get_next(root2, t);
            int d1 = t - left, d2 = right - t;
            if (d1 <= d2) {
                remove(root2, left);
                remove(root1, t);
            } else {
                remove(root2, right);
                remove(root1, t);
            }
            sza--, szb--;
            res += min(d1, d2);
        }
        while (szb <= sza and szb) {
            auto t = get_next(root2,-INF+1);
            auto left = get_prev(root1, t);
            auto right = get_next(root1, t);
            int d1 = t - left, d2 = right - t;
            if (d1 <= d2) {
                remove(root1, left);
                remove(root2, t);
            } else {
                remove(root1, right);
                remove(root2, t);
            }
            sza--, szb--;
            res += min(d1, d2);
        }
        res %= 1000000;

    }
    cout << res << nline;
}
posted @ 2022-03-31 20:34  指引盗寇入太行  阅读(16)  评论(0编辑  收藏  举报