CodeForces 920E Connected Components?

洛谷传送门

CF 传送门

考虑直接暴力 dfs。设搜到点 \(u\),把 \(u\) 打上 tag,然后我们枚举 \(v\) 使得 \(v\) 没被打上 tag 且边 \((u, v)\) 不存在,搜点 \(v\) 即可。复杂度 \(O(n^2)\)

发现瓶颈在于寻找没被打上 tag 的点。考虑使用链表,维护还没被打上 tag 的点,搜到 \(u\) 时将 \(u\) 从链表中删除,再遍历一遍链表即可。

实现时可以用并查集模拟链表。时间复杂度 \(O((n + m) \log n)\)

code
// Problem: E. Connected Components?
// Contest: Codeforces - Educational Codeforces Round 37 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/920/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

int n, m;
bool vis[maxn];
set<int> S[maxn];

struct DSU {
	int fa[maxn], sz[maxn];
	
	inline void init() {
		for (int i = 1; i <= n + 1; ++i) {
			fa[i] = i;
			sz[i] = 1;
		}
	}
	
	int find(int x) {
		return fa[x] == x ? x : fa[x] = find(fa[x]);
	}
	
	inline void merge(int x, int y) {
		x = find(x);
		y = find(y);
		if (x != y) {
			fa[x] = y;
			sz[y] += sz[x];
		}
	}
} D, d;

void dfs(int u) {
	vis[u] = 1;
	D.fa[u] = u + 1;
	for (int v = D.find(1); v <= n; v = D.find(v + 1)) {
		if (S[u].find(v) == S[u].end()) {
			d.merge(u, v);
			dfs(v);
		}
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	while (m--) {
		int u, v;
		scanf("%d%d", &u, &v);
		S[u].insert(v);
		S[v].insert(u);
	}
	D.init();
	d.init();
	for (int i = 1; i <= n; ++i) {
		if (!vis[i]) {
			dfs(i);
		}
	}
	vector<int> ans;
	for (int i = 1; i <= n; ++i) {
		if (d.fa[i] == i) {
			ans.pb(d.sz[i]);
		}
	}
	sort(ans.begin(), ans.end());
	printf("%d\n", (int)ans.size());
	for (int x : ans) {
		printf("%d ", x);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2023-07-10 19:17  zltzlt  阅读(18)  评论(0编辑  收藏  举报