题目地址:
https://www.acwing.com/problem/content/839/
给定一个包含
n
n
n个点(编号为
1
∼
n
1\sim n
1∼n)的无向图,初始时图中没有边。接下来进行
m
m
m次操作,每次操作:
(1)“C a b”,在点
a
a
a和点
b
b
b之间连一条边,
a
a
a和
b
b
b可能相等;
(2)“Q1 a b”,询问点
a
a
a和点
b
b
b是否在同一个连通块中,
a
a
a和
b
b
b可能相等;
(3)“Q2 a”,询问点
a
a
a所在连通块中点的数量;
输入格式:
第一行输入整数
n
n
n和
m
m
m。接下来
m
m
m行,每行包含一个操作指令,指令为“C a b”,“Q1 a b”或“Q2 a”中的一种。
输出格式:
对于每个询问指令”Q1 a b”,如果
a
a
a和
b
b
b在同一个连通块中,则输出“Yes”,否则输出“No”。对于每个询问指令“Q2 a”,输出一个整数表示点
a
a
a所在连通块中点的数量每个结果占一行。
数据范围:
1
≤
n
,
m
≤
1
0
5
1\le n,m\le 10^5
1≤n,m≤105
用带统计连通块点数量的并查集。代码如下:
#include <iostream>
using namespace std;
const int N = 100010;
int p[N], sz[N];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int x, int y) {
int px = find(x), py = find(y);
if (px == py) return;
p[px] = py;
sz[py] += sz[px];
}
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
p[i] = i;
sz[i] = 1;
}
while (m--) {
char op[2];
int x, y;
cin >> op;
if (op[0] == 'C') {
cin >> x >> y;
merge(x, y);
} else if (op[0] == 'Q') {
if (op[1] == '1') {
cin >> x >> y;
find(x) == find(y) ? puts("Yes") : puts("No");
} else if (op[1] == '2') {
cin >> x;
printf("%d\n", sz[find(x)]);
}
}
}
}
每次操作时间复杂度 O ( log ∗ n ) O(\log ^*n) O(log∗n),空间 O ( n ) O(n) O(n)。