BZOJ#1208[HNOI2004]宠物收养场
[HNOI2004]宠物收养场
思路:
使用两个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;
}