20200628 T3 网络检查

题目描述

\(\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\) 行,每行一个正整数,描述对应测试的结果。

样例

1.in

3 4
1 2
2 3
1 3
3 1
3
1 2
2 4
3 4

1.out

2
2
1

2.in

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

2.out

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]\) 中的边用并查集维护一下最后看有多少个块就行了。

Code

#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;
}
posted @ 2020-06-28 21:20  yu__xuan  阅读(156)  评论(0编辑  收藏  举报