一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
二、解题报告
1、思路分析
如果直接求最小生成树会怎样呢?
如果得到的最小生成树中存在大于k的边,那么我们的答案就是他们的权值 - k 的和
如果得到的最小生成树中没有大于k的边,我们把边集数组中abs(w - k)最小的边拿进来,会得到一个环,删去任意一条边,那么我们又得到一颗生成树,此时答案为min(abs(w - k))
分析第二种情况的正确性,拿进来的边要么是我们MST中的最大边权边,要么是不在MST中abs(w - k)最小的边,所以一定是正确解
2、复杂度
时间复杂度: O(MlogM)空间复杂度:O(M)
3、代码详解
#include <bits/stdc++.h>
#include <ranges>
// #define DEBUG
using i64 = long long;
using u32 = unsigned;
using u64 = unsigned long long;
constexpr int inf32 = 1E9 + 7;
constexpr i64 inf64 = 1E18 + 7;
constexpr double eps = 1e-9;
struct DSU {
std::vector<int> p;
int n, sz;
DSU(int _n) : p(_n, -1), n(_n), sz(_n) {}
void init () {
p.assign(n, -1);
}
int find(int x) {
return p[x] < 0 ? x : p[x] = find(p[x]);
}
bool merge(int x, int y) {
int px = find(x), py = find(y);
if (px == py) return false;
if (p[px] > p[py]) std::swap(px, py);
p[px] += p[py], p[py] = px;
-- sz;
return true;
}
int size(int x) {
return -p[find(x)];
}
int size() const {
return sz;
}
};
void solve() {
int n, m, k;
std::cin >> n >> m >> k;
std::vector<std::array<int, 3>> edges(m);
i64 mi = inf64;
for (int i = 0, a, b, c; i < m; ++ i) {
std::cin >> a >> b >> c;
edges[i] = { a - 1, b - 1, c };
mi = std::min<i64>(mi, abs(c - k));
}
std::ranges::sort(edges, [](auto& a, auto& b) -> bool {
return a[2] < b[2];
});
DSU dsu(n);
i64 res = 0;
for (auto& [a, b, c] : edges) {
if (dsu.merge(a, b))
res += std::max(0, c - k);
}
std::cout << (res ? res : mi) << '\n';
}
auto FIO = []{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
} ();
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int t = 1;
std::cin >> t;
while (t --)
solve();
return 0;
}