小 \(\text{L}\) 是一位网络爱好者,\(\text{TA}\) 有 \(n\) 台能接入网络的设备,编号为 \(1,2,\dots,n\);还有 \(m\) 条连接它们的线缆,编号为 \(1,2,\dots,m\)。每条线缆都可以在连接的两台设备间双向传输数据。
在建成网络之后,小 \(\text{L}\) 开始担心网络的安全问题。\(\text{TA}\) 希望测试一下这个网络的抗干扰能力,于是准备了 \(q\) 次测试:给定两个参数 \(l_i\) 和 \(r_i\),小 \(\text{L}\)会询问当所有编号在 \(l_i\) 和 \(r_i\) 之间的线缆都断开的时候,整个网络会分成多少块,满足同一块内的任意两台设备都能互相发送数据,而不同块间的任意两台设备都不能互相发送数据。注意测试之间是相互独立的,在某次测试中断开的线缆会在这一次测试结束后立即再连回去。
小 \(\text{L}\) 马上开始动手测试,但 \(\text{TA}\) 发现工作量实在太大了,自己完不成,于是 \(\text{TA}\) 找到了你。请你根据小 \(\text{L}\) 给出的网络描述和测试描述,回答每次测试的结果。
第一行输入两个正整数 \(n\) 和 \(m\),表示网络中的设备数和线缆数。
接下来 \(m\) 行,第 \(i\) 行包含两个正整数 \(x\) 和 \(y\)(\(x \neq y\)),表示编号为 \(i\) 的线缆连接了编号为 \(x\) 和 \(y\) 的设备。两台设备间可能有多于一条线缆。
下一行包含一个正整数 \(q\),表示测试的个数。接下来 \(q\) 行,每行两个正整数 \(l_i\) 和 \(r_i\),描述一次测试。
输出 \(q\) 行,每行一个正整数,描述对应测试的结果。
3 4
1 2
2 3
1 3
3 1
3
1 2
2 4
3 4
2
2
1
6 5
1 2
5 4
2 3
3 1
3 6
6
1 3
2 5
1 5
5 5
2 4
3 3
4
5
6
3
4
2
对于 \(30\%\) 的数据,\(n \leq 50,m,q \leq 1000\);
对于另外 \(30\%\) 的数据,只有不超过 \(100\) 个不同的 \(l_i\);
对于 \(100\%\) 的数据,\(2 \leq n \leq 500,1 \leq m \leq 10^4,1 \leq q \leq 2 * 10 ^ 4\)
并查集。把全部的边从前往后扫一遍,找到能让不连通的两块变得连通的几条边,从后往前也进行一遍。这样我们就找到了从前往后以及从后往前第一条能使 \(u\) 和 \(v\) 两个不连通的块变得连通的边,对于每次断边 \([l,r]\) ,我们从之前存下的从前往后以及从后往前第一条能使 \(u\) 和 \(v\) 两个不连通的块变得连通的边中找到不在 \([l,r]\) 中的边用并查集维护一下最后看有多少个块就行了。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 10001
int n, m, q, u[MAXN], v[MAXN];
int fa[501], size[501];
int pf[MAXN], sf[MAXN];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void Union(int x, int y) {
int rootx = find(x), rooty = find(y);
if (rootx == rooty) return;
if (size[rootx] > size[rooty]) {
size[rootx] += size[rooty];
fa[rooty] = rootx;
}
else {
size[rooty] += size[rootx];
fa[rootx] = rooty;
}
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i) fa[i] = i, size[i] = 0;
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &u[i], &v[i]);
}
for (int i = 1; i <= m; ++i) {
if (find(u[i]) != find(v[i])) {
Union(u[i], v[i]);
pf[++pf[0]] = i;
}
}
for (int i = 1; i <= n; ++i) fa[i] = i, size[i] = 0;
for (int i = m; i >= 1; --i) {
if (find(u[i]) != find(v[i])) {
Union(u[i], v[i]);
sf[++sf[0]] = i;
}
}
scanf("%d", &q);
for (int i = 1, x, y, ans = 0; i <= q; ++i) {
for (int j = 1; j <= n; ++j) fa[j] = j, size[j] = 0;
scanf("%d %d", &x, &y), ans = 0;
for (int j = 1; j <= pf[0] && pf[j] < x; ++j) {
Union(u[pf[j]], v[pf[j]]);
}
for (int j = 1; j <= sf[0] && sf[j] > y; ++j) {
Union(u[sf[j]], v[sf[j]]);
}
for (int j = 1; j <= n; ++j) {
if (fa[j] == j) ++ans;
}
printf("%d\n", ans);
}
return 0;
}
原文:https://www.cnblogs.com/poi-bolg-poi/p/13205103.html