AcWing 837. 连通块中点的数量
\(AcWing\) \(837\). 连通块中点的数量
一、题目描述
给定一个包含 \(n\) 个点(编号为 \(1∼n\))的无向图,初始时图中没有边。
现在要进行 \(m\) 个操作,操作共有三种:
C a b
,在点a
和点b
之间连一条边,a
和b
可能相等;Q1 a b
,询问点a
和点b
是否在同一个连通块中,a
和b
可能相等;Q2 a
,询问点a
所在连通块中点的数量;
输入格式
第一行输入整数 \(n\) 和 \(m\)。
接下来 \(m\) 行,每行包含一个操作指令,指令为 C a b
,Q1 a b
或 Q2 a
中的一种。
输出格式
对于每个询问指令 Q1 a b
,如果 \(a\) 和 \(b\) 在同一个连通块中,则输出 Yes
,否则输出 No
。
对于每个询问指令 Q2 a
,输出一个整数表示点 \(a\) 所在连通块中点的数量
每个结果占一行。
数据范围
\(1≤n,m≤10^5\)
输入样例:
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
输出样例:
Yes
2
3
二、题目解析
并查集 + 附加信息,附加信息为家族中成员的数量,需要一个额外的数组\(s[N]\)记录以结点\(i\)为根的的家族成员数量。
与最祼并查集的区别:
-
初始化时需要将\(s[i]=1\)
-
合并时,需要\(s[find(b)]+ =s[find(a)]\)
-
查询时:\(s[find(a)]\)
三、实现代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m;
int p[N];
int s[N];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) p[i] = i, s[i] = 1;
while (m--) {
string op;
int a, b;
cin >> op;
if (op == "C") {
cin >> a >> b;
if (find(a) != find(b)) {
s[find(b)] += s[find(a)];
p[find(a)] = find(b);
}
} else if (op == "Q1") {
cin >> a >> b;
if (find(a) == find(b))
puts("Yes");
else
puts("No");
} else {
cin >> a;
printf("%d\n", s[find(a)]);
}
}
return 0;
}