题解:AT_abc392_e [ABC392E] Cables and Servers
考虑将服务器作为顶点、电缆作为边构成的图。
对于每个连通分量,找到属于它的顶点以及多余的边。
这通过 DFS 或 BFS 实现,也可以用并查集来完成。
修改多余边的一端总是会减少连通分量的数量。反之,无论边如何修改,连通分量的数量最多只会改变一个。
因此,重复这种修改可以最小化所需的操作次数。
可以通过优先考虑具有更多多余边的连通分量来实现点。
#include <bits/stdc++.h>
#include <atcoder/dsu>
#define int long long
using namespace std;
inline int read()
{
int f = 0, ans = 0;
char c = getchar();
while (!isdigit(c))
f |= c == '-', c = getchar();
while (isdigit(c))
ans = (ans << 3) + (ans << 1) + c - 48, c = getchar();
return f ? -ans : ans;
}
void write(int x)
{
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
constexpr int N = 2e5 + 5;
int n, m;
pair<int, int> e[N];
signed main()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
n = read(), m = read();
atcoder::dsu d(n + 1);
vector<int> id;
for (int i = 1; i <= m; ++i)
{
int u = read(), v = read();
e[i] = {u, v};
if (d.same(u, v))
id.emplace_back(i);
else
d.merge(u, v);
}
set<int> ldr;
vector<tuple<int, int, int>> ans;
for (int i = 1; i <= n; ++i)
if (d.leader(i) == i)
ldr.insert(i);
for (int &i : id)
{
if (size(ldr) == 1)
break;
ldr.erase(d.leader(e[i].first));
ans.push_back({i, e[i].second, *begin(ldr)});
d.merge(d.leader(e[i].first), *begin(ldr));
ldr.erase(begin(ldr));
ldr.insert(d.leader(e[i].first));
}
write(size(ans)), putchar('\n');
for (auto &[x, y, z] : ans)
write(x), putchar(' '), write(y), putchar(' '), write(z), putchar('\n');
return 0;
}