CF292D Connected Components(并查集前缀和)

Description

给定一张 n n 个点 m m 条边的无向图,有 k k 次询问,每次询问参数将第 [ l , r ] [l,r] 的边删除,求这时有多少个联通分量。

1 n 500 , 1 m 1 0 4 , 1 k 2 × 1 0 4 1 \leq n \leq 500, 1 \leq m \leq 10^4, 1\leq k \leq 2 \times 10^4

Solution

数据有点水,每次把可用的边取出来用并查集求也可以卡过去。考虑优化,可以预处理并查集的前缀和后缀和。这样时间复杂度从 O ( k m log n ) O(km \log n) 优化到了 O ( k n log n ) O(kn \log n) 。这空间换时间的做法学到了。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 5, M = 1e4 + 5, INF = 0x3f3f3f3f;
inline int read() {
	int x = 0, f = 0; char ch = 0;
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}
int n, m;
int x[M], y[M];
struct node {
    int f[N], cnt;
    node() {
    	for (int i = 1; i < N; i++) f[i] = i;
    }
    int find(int x)  {
    	if (f[x] == x) return x;
    	return f[x] = find(f[x]);
    }
	void merge(int x, int y) {
		x = find(x), y = find(y);
		if (x != y) f[x] = y, cnt++;
	}
} pre[M], suf[M];
int main() {
    n = read(), m = read();
    for (int i = 1; i <= m; i++) {
    	x[i] = read(), y[i] = read();
		pre[i] = pre[i - 1], pre[i].merge(x[i], y[i]); 
    }
    for (int i = m; i; i--) suf[i] = suf[i + 1], suf[i].merge(x[i], y[i]);
    int Q = read();
    while (Q--) {
        int l = read(), r = read();
        node dsu = pre[l - 1];
        for (int i = 1; i <= n; i++)
            if (suf[r + 1].f[i]) dsu.merge(i, suf[r + 1].f[i]);
        printf("%d\n", n - dsu.cnt);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39984146/article/details/104697972