并查集

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
#include <iostream>
#include <cstring>
using namespace std;

const int MAX_SIZE = 10001;
//unionSet[i] = -1: i 为单个结点
//unionSet[i] = x < -1: i 为根节点,-x 表示树大致的高度
//unionSet[i] = x >= 0: x 是 i 的父节点
int unionSet[MAX_SIZE];
int size;

/**
* 给定并查集中某个元素,查找它的根节点
*/
int Find(int elem)
{
//没有父节点,说明 elem 自己就是一个根节点
if (unionSet[elem] < 0)
return elem;
//查找根节点,顺便做路径压缩
else
return unionSet[elem] = Find(unionSet[elem]);
}

void Union(int elem1, int elem2)
{
int root1 = Find(elem1);
int root2 = Find(elem2);
if (root1 == root2)
return;
int subTree, newRoot;
//要把高度低的树挂载到高度高的树上去,从而维护查找结构的平衡
if (unionSet[root1] < unionSet[root2])
{
newRoot = root1;
subTree = root2;
}
else
{
newRoot = root2;
subTree = root1;
}
//挂
unionSet[subTree] = newRoot;
//如果原来高度一样,那么新的树高度就会增高
if (unionSet[root1] == unionSet[root2])
unionSet[newRoot]--;
}

int main()
{
int n, m;
ios::sync_with_stdio(false);
int z, x, y;
while (cin >> n >> m)
{
//初始化设置,-1 表示初始单个结点的高度为 1
memset(unionSet, -1, sizeof(int) * n);
//当Zi=1时,将Xi与Yi所在的集合合并
//当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N
for (int i = 0; i < m; ++i)
{
cin >> z >> x >> y;
if (z == 1)
Union(x, y);
else if (z == 2)
{
if (Find(x) == Find(y))
cout << "Y" << endl;
else
cout << "N" << endl;
}
}
}
return 0;
}