2020牛客多校三 G. Operating on a Graph (并查集+启发式合并)

题意:2020牛客多校三 G. Operating on a Graph (并查集+启发式合并)_第1张图片

题解:并查集+启发式合并
每次将给出集合的所有相邻集合纳入到自身。

我们可以发现,每个点只会产生一次贡献,即若询问的是该点,那么之后该点与其相邻点永远同集合。

用并查集维护属于哪个集合,再用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;
}

你可能感兴趣的:(#,并查集)