题解 | #小欧皇#
小欧皇
https://www.nowcoder.com/practice/6afe13c512d44b30b03933471d259ba4
每个连通块对答案的贡献是固定的,如果连通块内有 n 个点,那么答案就是 n*(n-1)/2 ,所以我们可以用并查集维护出所有的连通块,然后维护出初始的答案,然后枚举剩下的所有为 0 的点变成 1 以后的情况,他会连接所有的相邻的 1 的连通块
#include <bits/stdc++.h> using namespace std; #define int long long const int INF = 1e18; const int N = 1e5 + 5; int __t = 1, n, u, v, sum, m, f[N], w[N], vis[N]; string s; vector<int> g[N]; int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } void mg(int x, int y) { x = find(x), y = find(y); if (x != y) { f[x] = y; w[y] += w[x]; } } void solve() { cin >> n >> m; for (int i = 1; i <= n; i++) f[i] = i, w[i] = 1; cin >> s; s = " " + s; for (int i = 0; i < m; i++) { cin >> u >> v; g[u].push_back(v); g[v].push_back(u); if (s[u] == '1' && s[v] == '1') mg(u, v); } for (int i = 1; i <= n; i++) { if (s[i] == '1') { int fa = find(i); if (!vis[fa]) { vis[fa] = 1; sum += w[fa] * (w[fa] - 1) / 2; } } } int ansi = 0, anssum = 0; for (int i = 1; i <= n; i++) { if (s[i] == '0') { map<int, int> mp; int ssum = sum, num = 1; for (int v : g[i]) { if (s[v] == '1') { int x = find(v); if (mp[x]) continue; mp[x] = 1; ssum -= w[x] * (w[x] - 1) / 2; num += w[x]; } } ssum += num * (num - 1) / 2; if (ssum > anssum) { anssum = ssum; ansi = i; } } } cout << ansi << " " << anssum << "\n"; } int32_t main() { #ifdef ONLINE_JUDGE ios::sync_with_stdio(false); cin.tie(0); #endif // cin >> __t; while (__t--) solve(); return 0; }