E - Divide Graph Editorial by en_translator
First, the condition that “the number of connected components of \(G\) becomes exactly \(2\)” can be replaced to “\(G\) becomes disconnected.” This condition is strictly looser than the original, but since we are minimizing the total cost of the edges to remove, making the number of connected components three or more is not beneficial, so this replacement does not change the optimal answers.
Next, by considering the edges that we are not removing, the problem can be rephrased as follows:
- You are given a weighted undirected graph \(G\). When you some of the edges of \(G\) so that retaining them (and removing the others) makes \(G\) disconnected, what is the maximum possible total weight of the chosen edges?
Note that the answer to the original problem is obtained by subtracting the answer to above from \(\sum_{i=1}^{N} 2^i\).
While this problem is not easy in general, in our case edge \(i\) has weight \(2^i\), which justifies the following greedy algorithm:
- Let \(G\) initially have no edges. For \(i=M,M-1,\dots,1\), do the following:
- Add edge \(i\) to \(G\) if and only if adding it does not make \(G\) connected. If the edge is added, add \(2^i\) to the answer.
Hence, the problem can be solved by simulating this greedy algorithm using a data structure that manages connectivity, such as Disjoint Set Union (DSU).
Sample code (C++):
#include <bits/stdc++.h>
#include <atcoder/dsu>
#include <atcoder/modint>
using namespace std;
using mint = atcoder::modint998244353;
int main() {
int n, m;
cin >> n >> m;
vector<int> u(m), v(m);
vector<mint> cost(m);
for (int i = 0; i < m; i++) {
cin >> u[i] >> v[i];
--u[i], --v[i];
cost[i] = (i ? cost[i - 1] * 2 : 2);
}
atcoder::dsu uf(n);
mint ans = 0;
int cnt = n;
for (int i = m - 1; i >= 0; i--) {
if (!uf.same(u[i], v[i])) {
if (cnt > 2) {
uf.merge(u[i], v[i]);
--cnt;
} else {
ans += cost[i];
}
}
}
cout << ans.val() << endl;
}
posted:
last update: