题解:并查集+启发式合并
每次将给出集合的所有相邻集合纳入到自身。
我们可以发现,每个点只会产生一次贡献,即若询问的是该点,那么之后该点与其相邻点永远同集合。
用并查集维护属于哪个集合,再用vector存储该集合的外部连接点是哪几个。
更新外部结点的时候我们按照集合大小来合并,不然超内存。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int t, n, m, u, v, x, q;
const int Max = 8e5 + 5;
int Parent[Max];
int Find(int x) {
return Parent[x] == x ? x : Parent[x] = Find(Parent[x]);
}
void Union(int x, int y) {
int u, v, root;
u = Find(x);
v = Find(y);
if (u == v) return;
Parent[v] = u;
//return root;
}
vector<int> g[Max];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) Parent[i] = i, g[i].clear();
for (int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
scanf("%d", &q);
while (q--) {
scanf("%d", &x);
if (Find(x) != x) continue;
auto temp = g[x];
g[x].clear();
for (auto v : temp) {
int fa = Find(v);
if (fa == x) continue;
Union(x, fa);
if (g[x].size() < g[fa].size()) swap(g[x], g[u]); //按秩合并
g[x].insert(g[x].end(), g[fa].begin(), g[fa].end());
}
}
for (int i = 0; i < n; i++) printf("%d ", Find(i));
puts("");
}
return 0;
}