其他题解:1.分成好几个函数形式
模板: 维护size
的并查集:
int p[N], size[N];
p[]
存储每个点的祖宗节点,size[]
只有祖宗节点的size[]
才有意义,表示祖宗节点所在集合中的点的数量
返回x的祖宗节点
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++) {
p[i] = i;
size[i] = i;
}
合并a和b所在的两个集合:
p[find(a)] = find(b);
size[find(b)] += find(a);
nums[]
表示每一个集合的大小,集合是树,只保证根节点的nums
有意义,当合并两棵树时,是把一个树的根节点插在另一个树根下面,插完后,更新nums nums[b] += nums[a];
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int p[N], nums[N];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main () {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++) {
p[i] = i;
nums[i] = 1; //初始时,每个集合中只有一个点
}
while (m --) {
char op[5];
int a, b;
scanf("%s", op);
if (op[0] == 'C') { //在a和b之间连一条边
scanf("%d%d",&a, &b);
if (find(a) == find(b)) continue; //特判,如果a和b在同一个集合中,后面操作不用进行(自己指向自己),如果没有continue,下面那一步的意思将是a b在同一个集合,再做nums[find(b)]+=nums[find(a)],就会让元素数量翻倍,错误
nums[find(b)] += nums[find(a)];
p[find(a)] = find(b);
}
else if (op[1] == '1') { //表示Q1
scanf("%d%d", &a, &b);
if (find(a) == find(b)) puts("Yes");
else puts("No");
}
else { //统计某个点所在集合中点的数量
scanf("%d", &a);
printf("%d\n", nums[find(a)]); //想统计数量时,先找到该点的根节点可直接返回size[find(a)];
}
}
return 0;
}