public class 并查集 {
static int pre[]; // pre[n]记录节点n的父亲,如果n的父亲是n自身,则n是Root根节点
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(); // n个点
int m = in.nextInt(); // m条路径
pre = new int[n + 1];
for (int i = 1; i <= n; i++) { // 初始化 自身的父亲是自身
pre[i] = i;
}
for (int j = 0; j < m; j++) { // m条路径
int x = in.nextInt();
int y = in.nextInt();
// x和y连通
join(x, y);
}
// 看有多少棵不同root的树
Set set = new HashSet();
for (int i = 1; i < pre.length; i++) {
set.add(pre[i]);
}
System.out.println("至少需要修" + (set.size() - 1) + "条路");
}
// join 合并
public static void join(int x, int y) {
int xRoot = find(x);
int yRoot = find(y);
if (xRoot != yRoot) {
pre[xRoot] = yRoot;
}
}
// find 找到根节点
public static int find(int n) {
int r = n;
while (pre[r] != r) { // 如果自己的父亲不是自己,非root,继续查找
r = pre[r];
}
// 路径压缩 将所有子节点的父亲替换为root节点
int i = n, j;
while (i != r) { // 如果该节点的父亲不是root
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
}