Description
给定一张 个点 条边的无向图,有 次询问,每次询问参数将第 的边删除,求这时有多少个联通分量。
Solution
数据有点水,每次把可用的边取出来用并查集求也可以卡过去。考虑优化,可以预处理并查集的前缀和后缀和。这样时间复杂度从 优化到了 。这空间换时间的做法学到了。
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;
}