题解:P16071 [ICPC 2023 NAC] Broken Minimum Spanning Tree

题目

第一问比较简单。因为一次交换只能交换走 \(1\) 个不是最小生成树的原树边,所以答案就是原树里不属于最小生成树的边数。

第二问相比第一问就要保证每一次交换都要是生成树。我们考虑先将边分类:

  • \(-1\):代表这条边属于最小生成树但不在当前树。
  • \(1\):代表这条边不属于最小生成树但在当前树。
  • \(2\):代表这条边属于最小生成树也在当前树。
  • \(0\):代表这条边不属于最小生成树也不在当前树。

我们很容易发现 \(2\)\(0\) 是不用动的,需要的只有 \(1\)\(-1\)

我们每一次可以任意选择一条为 \(1\) 的边去除变为 \(0\),然后我们就发现树就被分割成两个连通块,此时我们要找的就是两点在不同连通块的 \(-1\) 的边。因为 \(n\leqslant2000,m\leqslant3000\),所以可以直接现把所有在当前树的边通过并查集合并,然后枚举即可。

证明显然。

#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m;
tuple<int, int, int, int, int> e[3005];
int f[N], sz[N];
int getf(int x) {
    return f[x] == x ? x : f[x] = getf(f[x]);
}
void merge(int x, int y) {
    x = getf(x), y = getf(y);
    if(sz[x] > sz[y]) swap(x, y);
    if(x == y) return;
    f[x] = y;
    sz[y] += sz[x];
}
void init() {
    for(int i = 1; i <= n; i++) f[i] = i, sz[i] = 1;
}
void kruskal() {
    init();
    sort(e + 1, e + 1 + m, [](tuple<int, int, int, int, int> a, tuple<int, int, int, int, int> b) {
        if(get<2>(a) == get<2>(b)) return get<3>(a) < get<3>(b);
        else return get<2>(a) < get<2>(b);
    });
    int cnt = 0;
    for(int i = 1; i <= m; i++) {
        if(getf(get<0>(e[i])) == getf(get<1>(e[i]))) {
            if(get<3>(e[i]) > n - 1) get<4>(e[i]) = 0;
            else get<4>(e[i]) = 1;
            continue;
        }
        merge(get<0>(e[i]), get<1>(e[i]));
        if(get<3>(e[i]) > n - 1) get<4>(e[i]) = -1, cnt++;
        else get<4>(e[i]) = 2;
    }
    cout << cnt << "\n";
    for(int i = 1; i <= m; i++) if(get<4>(e[i]) == 1) {
        init();
        get<4>(e[i]) = 0;
        for(int j = 1; j <= m; j++) if(get<4>(e[j]) >= 1) merge(get<0>(e[j]), get<1>(e[j]));
        for(int j = 1; j <= m; j++) if(get<4>(e[j]) == -1 && getf(get<0>(e[j])) != getf(get<1>(e[j]))) {
            cout << get<3>(e[i]) << " " << get<3>(e[j]) << "\n";
            get<4>(e[j]) = 2;
            break;
        }
    }
}
int main() {
    cin >> n >> m;
    for(int i = 1, u, v, w; i <= m && cin >> u >> v >> w; i++)
        e[i] = {u, v, w, i, 0};
    kruskal();
    return 0;
}
posted @ 2026-09-02 11:01  Monotonic_Deque  阅读(7)  评论(0)    收藏  举报