AT_abc352_e 题解

思路

首先显然不能 O(m2)O(\sum m^2) 暴力建边求最小生成树,要考虑更快的方法。让我们来回顾一下 kruskal 的实现过程:

  1. 先把所有边排序;
  2. 再按边权从小到大进行并查集,逐渐合并每个连通块,直到合并成一个块。

这个思路在这题中仍然可行。因为每个子集的所有边权是相同的,所以我们把所有子集按边权 cic_i 排序,然后把子集中的每个点与 ai,1a_{i,1} 合并一下就行了。最后不连通就无解。

代码

# 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;
}
posted @ 2024-05-06 15:54  Vitamin_B  阅读(7)  评论(0)    收藏  举报  来源