算法 BISHI102 【模板】并查集 思路 求解代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 // 存储节点 i 的父节点编号;当 parent[i] == i 时,i 为该集合的根节点 private static int[] parent; // 仅在 i 为根节点时有效,记录以 i 为根的集合中包含的元素总数 private static int[] size; public static void main(String[] args) throws IOException { // 使用高性能输入输出流 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); // 解析输入首行的 n (元素总数) 和 q (操作总数) String[] strA = br.readLine().trim().split("\\s+"); int n = Integer.parseInt(strA[0]); int q = Integer.parseInt(strA[1]); parent = new int[n + 1]; size = new int[n + 1]; for (int i = 1; i <= n; i++) { // 初始状态下,每个元素自成一个集合,父节点指向自己 parent[i] = i; // 每个初始集合的大小均为 1 size[i] = 1; } while (q-- > 0) { String[] strB = br.readLine().trim().split("\\s+"); int op = Integer.parseInt(strB[0]); // 操作类型编号 switch (op) { case 1: { // 合并操作:将 i 和 j 所在的两个集合合并为一个 int i = Integer.parseInt(strB[1]); int j = Integer.parseInt(strB[2]); union(i, j); break; } case 2: { // 判断 i 和 j 是否属于同一个集合 int i = Integer.parseInt(strB[1]); int j = Integer.parseInt(strB[2]); // 若两者的根节点相同,则在同一集合,输出 YES out.println(find(i) == find(j) ? "YES" : "NO"); break; } case 3: { // 获取 i 所在集合的元素总数 int i = Integer.parseInt(strB[1]); // 必须先通过 find(i) 找到根节点,因为只有根节点的 size 是准确的 out.println(size[find(i)]); break; } } } // 刷新缓冲区并释放 IO 资源 out.flush(); out.close(); br.close(); } /** * 查找元素 i 所在集合的根节点 * 在递归查找过程中,将路径上所有节点的父节点直接指向根节点 */ private static int find(int i) { // 如果自己就是根节点,直接返回 if (parent[i] == i) { return i; } // 将查找到的根节点赋值给当前节点的 parent 数组 return parent[i] = find(parent[i]); } /** * 将包含 i 和 j 的两个集合合并 * * @param i 第一个元素 * @param j 第二个元素 */ private static void union(int i, int j) { // 分别获取两个元素当前的根节点 int rootI = find(i); int rootJ = find(j); // 如果根节点不同,说明处于不同集合,执行合并 if (rootI != rootJ) { // 将 I 集合的根节点挂载到 J 集合的根节点之下 parent[rootI] = rootJ; // 将被合并集合的规模累加到新的根节点 (rootJ) 上 size[rootJ] += size[rootI]; } }