CF292D Connected Components(并查集前缀和)

Description

给定一张 n n n 个点 m m m 条边的无向图,有 k k k 次询问,每次询问参数将第 [ l , r ] [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 1n500,1m104,1k2×104

Solution

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

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值