一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
一、题目描述:
给定一个包含 n 个点(编号为 1∼n)的无向图,初始时图中没有边。
现在要进行 m 个操作,操作共有三种:
C a b,在点 aa 和点 bb 之间连一条边,a 和 b 可能相等;Q1 a b,询问点 aa 和点 bb 是否在同一个连通块中,a 和 b 可能相等;Q2 a,询问点 a 所在连通块中点的数量;输入格式
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为
C a b,Q1 a b或Q2 a中的一种。输出格式
对于每个询问指令
Q1 a b,如果 aa 和 bb 在同一个连通块中,则输出Yes,否则输出No。对于每个询问指令
Q2 a,输出一个整数表示点 a 所在连通块中点的数量每个结果占一行。
数据范围
输入样例:
5 5 C 1 2 Q1 1 2 Q2 1 C 2 5 Q2 5输出样例:
Yes 2 3
二、思路分析:
这一题就是 并查集的应用,题目在并查集的两个基本操作中又维护了一个size数组来表示连通块中点的个数。
操作很简单,一开始初始化点的个数为1,在之后连通两个点的操作中把并入的连通块中点的数量加到目标集合中。
PS: 在我们增加连通块时要判断两个点是否在同一集合中,如果在则不增加
三、AC 代码:
package acwing;
import java.util.Scanner;
public class acwing_837 {
static int n,m;
static int[] p = null;
static int[] size =null;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String[] nm = in.nextLine().split(" ");
n = Integer.parseInt(nm[0]); m = Integer.parseInt(nm[1]);
size = new int[ n + 1];
/** 初始化p数组,size数组 */
p = new int[ n + 1];
for (int i = 1; i < n + 1 ; i++) {
p[i] = i;
size[i] = 1;
}
for (int i = 0; i < m; i++) {
String[] s = in.nextLine().split(" ");
if (s[0].equals("C")) {
int a = find(Integer.parseInt(s[1]));
int b = find(Integer.parseInt(s[2]));
// 如果a=b则位于同一个集合中,则不增加集合中点的数量
if (a == b) {
continue;
}else{
p[a] = b;
size[b] += size[a];
}
}else if (s[0].equals("Q1")) {
int a = find(Integer.parseInt(s[1]));
int b = find(Integer.parseInt(s[2]));
if (find(a) == find(b)) {
System.out.println("Yes");
}else{
System.out.println("No");
}
}else{
System.out.println(size[find(Integer.parseInt(s[1]))]);
}
}
}
private static int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
}