题解 | #小欧皇#
小欧皇
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;
}
查看6道真题和解析
