Road Reform
题意
给你一个 n n n 个顶点 m m m 条边的无向图 (没有重边) 要求删掉 m − ( n − 1 ) m - (n - 1) m−(n−1) 条边使得图仍联通 并且权值最大的边与 k k k 的差值最小
思路
先把所有小于等于 k k k 的边加入新图 然后判断是否连通
如果已经联通 那么有两种选择
1.将已经加入的最大边权增大到 k k k
2.将大于 k k k 的第一条边加入 并且减少到 k k k
如果没有联通 那么按照边权递增的顺序加入边 直到联通为止
代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define endl '\n'
using namespace std;
typedef long long LL;
typedef pair<int, int>PII;
inline LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
const int N = 200010;
int n, m, k;
int f[N];
struct Node {
int u, v, w;
}node[N];
void init() {
for (int i = 0; i < N; ++i)f[i] = i;
}
int Find(int x) {
return x == f[x] ? x : f[x] = Find(f[x]);
}
void merge(int a, int b) {
f[Find(a)] = Find(b);
}
bool cmp(Node a, Node b) {
return a.w < b.w;
}
void solve() {
cin >> n >> m >> k;
init();
for (int i = 1; i <= m; ++i) {
int a, b, c; scanf("%d%d%d", &node[i].u, &node[i].v, &node[i].w);
}
sort(node + 1, node + m + 1, cmp);
int cnt = 0;
int i;
for (i = 1; i <= m; ++i) {
if (node[i].w > k)break;
int fa = Find(node[i].u);
int fb = Find(node[i].v);
if (fa != fb) {
merge(fa, fb);
cnt++;
}
}
//cout << node[i - 1].w << " " << node[i].w << endl;
if (cnt == n - 1) {
int res = k - node[i - 1].w;
if (i <= m)res = min(res, node[i].w - k);
printf("%d\n", res);
}
else {
LL res = 0;
for (int j = i; j <= m; ++j) {
int fa = Find(node[j].u);
int fb = Find(node[j].v);
if (fa != fb) {
cnt++;
merge(fa, fb);
res += node[j].w - k;
}
if (cnt == n - 1)break;
}
cout << res << endl;
}
}
int main() {
int t; cin >> t;
while(t--)
solve();
return 0;
}