B MST
参考了题解的做法,暴力
按照每次询问的点集中点的个数进行分类
对于大于的点集,遍历所有的初始边,存储两端点都位于点集中的边,排序后用Prim求出答案
对于小于的点集,对点集中的点两两结合,并存储其合法的边,排序后用Prim求出答案
code
struct P {
int u, v, w;
bool operator < (const P& a) const {
return w < a.w;
}
};
int fa[N];
int find(int u) {
return u == fa[u] ? u : fa[u] = find(fa[u]);
}
void solve() {
int n, m, q;
cin >> n >> m >> q;
int sz = sqrt(m / log2(m));
vector<P> e(m + 1);
map<pii, int>mp;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
e[i] = P{ u, v, w };
mp[pii(u, v)] = mp[pii(v, u)] = w;
}
sort(e.begin(), e.end());
while (q--) {
int k;
cin >> k;
vector<int> a(k), vis(n + 1, 0);
vector<P> EE;
for (int i = 0; i < k; i++)
cin >> a[i];
if (k < sz) {
for (int i = 0; i < k; i++) {
for (int j = i + 1; j < k; j++) {
if (mp.count(pii(a[i], a[j])))
EE.push_back({ a[i], a[j], mp[pii(a[i], a[j])] });
}
}
}
else {
for (auto it : a)
vis[it] = 1;
for (int i = 1; i <= m; i++) {
if (vis[e[i].u] && vis[e[i].v])
EE.push_back(e[i]);
}
}
int cnt = EE.size();
sort(EE.begin(), EE.end());
for (auto it : a)
fa[it] = it;
int ans = 0, sum = 0;
for (auto p : EE) {
if (sum >= k - 1)
break;
if (find(p.u) == find(p.v))
continue;
fa[find(p.u)] = find(p.v);
ans += p.w, sum++;
}
if (sum < k - 1)
cout << -1 << '\n';
else
cout << ans << '\n';
}
}