# bzoj2654: tree(最小生成树+二分)

bzoj2654: tree

## 解析

kruscal在做最小生成树时先按权值排序，权值小的先被选到，我们可以通过控制白色边的边权来控制白色边的数量。

1. 不要忘记减去给白边加的值
2. 排序时白边优先

## 代码

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n, m, num, need, ans, tot, sum, cnt;

struct node {
int u, v, w, col;
bool operator <(const node &oth) const {
return w == oth.w ? col < oth.col : w < oth.w;
}
} e[N], tmp[N];

int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int kruscal() {
cnt = 0, sum = 0, ans = 0;
for (int i = 1; i <= n; ++i) fa[i] = i;
sort(e + 1, e + 1 + m);
for (int i = 1; i <= m; ++i) {
int x = find(e[i].u), y = find(e[i].v);
if (x == y) continue;
fa[x] = y;
ans += e[i].w;
if (!e[i].col) sum++;
cnt++;
if (cnt == n - 1) break;
}
return sum;
}

bool check(int x) {
for (int i = 1; i <= m; ++i) {
e[i] = tmp[i];
if (!e[i].col) e[i].w += x;
}
return kruscal() >= need;
}

int main() {
ios::sync_with_stdio(false);
cin >> n >> m >> need;
for (int i = 1, x, y, z, c; i <= m; ++i) {
cin >> x >> y >> z >> c;
e[i] = (node) {x + 1, y + 1, z, c};
tmp[i] = (node) {x + 1, y + 1, z, c};
}
int l = -1000, r = 1000;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) l = mid + 1, tot = ans - need * mid;
else r = mid - 1;
}
cout << tot;
return 0;
}

posted @ 2019-07-21 22:04  Chrety  阅读(71)  评论(0编辑  收藏