AT_abc352_e 题解
思路
首先显然不能 暴力建边求最小生成树,要考虑更快的方法。让我们来回顾一下 kruskal 的实现过程:
- 先把所有边排序;
- 再按边权从小到大进行并查集,逐渐合并每个连通块,直到合并成一个块。
这个思路在这题中仍然可行。因为每个子集的所有边权是相同的,所以我们把所有子集按边权 排序,然后把子集中的每个点与 合并一下就行了。最后不连通就无解。
代码
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
int n, m, k[200005], c[200005], id[200005], f[200005], x, y, tot = 1;
vector <int> v[200005];
ll sum;
int find (int x) {
return x == f[x] ? x : f[x] = find (f[x]);
}
bool cmp (const int& x, const int& y) {
return c[x] < c[y];
}
int main () {
ios::sync_with_stdio (0);
cin.tie (0);
cout.tie (0);
cin >> n >> m;
for (int i = 1; i <= n; ++ i)
f[i] = i;
for (int i = 0; i < m; ++ i) {
id[i] = i;
cin >> k[i] >> c[i];
for (int j = 0; j < k[i]; ++ j)
cin >> x, v[i].emplace_back (x);
}
sort (id, id + m, cmp);
for (int i = 0; i < m; ++ i) {
x = v[id[i]][0];
for (int j = 1; j < k[id[i]]; ++ j) {
y = v[id[i]][j];
if (find (x) != find (y)) {
f[find (x)] = find (y);
++ tot;
sum += c[id[i]];
}
}
}
cout << (tot < n ? -1 : sum);
return 0;
}

浙公网安备 33010602011771号