并查集是一种用于处理一些不相交集合(Disjoint Sets)的合并及查询问题的树形数据结构,可以高效的解决多个元素的集合应用问题中:
合并集合、查询某元素属于某集合的问题
并查集的基本函数:
初始化:
1 void init()//未进行操作时没一个元素的祖先的是他自己
2 {
3 for (int i = 1; i <= n; i++)
4 f[i] = i;
5 }
查找:
1 int find(int x)//如果还没有查找到根节点(f[x]==x)
2 { //就不断递归查找x的祖先的祖先(f[x]=find(find[x]))
3 return f[x] == x ? x : f[x] = find(f[x]);
4 }
合并:
1 void merge(int a, int b)
2 {
3 int x = find(a);
4 int y = find(y);
5 if (x != y)
6 f[y] = x;
7 }
基础并查集:
1 #include<iostream>
2 using namespace std;
3 const int maxn = 100010;
4 int n, m, p, f[maxn];
5 void init()
6 {
7 for (int i = 1; i <= n; i++)
8 f[i] = i;
9 }
10 int find(int x)
11 {
12 return f[x] == x ? x : find(f[x]);
13 }
14 void merge(int a, int b)
15 {
16 int x = find(a);
17 int y = find(b);
18 if (x != y)
19 f[y] = x;
20 }
21 int main()
22 {
23 cin >> n >> m >> p;
24 init();
25 for (int i = 1; i <= m; i++)
26 {
27 int a, b;
28 cin >> a >> b;
29 merge(a, b);
30 }
31 for (int i = 1; i <= p; i++)
32 {
33 int a, b;
34 cin >> a >> b;
35 if (find(a) == find(b))
36 cout << "Yes" << endl;
37 else
38 cout << "No" << endl;
39 }
40 return 0;
41 }
拓展并查集:
例题:洛谷 P1525 关押罪犯
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 using namespace std;
5 int n, m;
6 struct people
7 {
8 int u, v, w;
9 }p[100010];
10 int f[100010];
11 int e[100010];
12 bool cmp(people a, people b)
13 {
14 return a.w > b.w;
15 }
16 int find(int x)
17 {
18 return f[x] == x ? x : f[x] = find(f[x]);
19 }
20 void merge(int a, int b)
21 {
22 int x = find(a);
23 int y = find(b);
24 if (x != y)
25 f[y] = x;
26 }
27 int main()
28 {
29 cin >> n >> m;
30 for (int i = 1; i <= n; i++)
31 f[i] = i;
32 for (int i = 1; i <= m; i++)
33 cin >> p[i].u >> p[i].v >> p[i].w;
34 sort(p + 1, p + 1 + m, cmp);
35 for (int i = 1; i <= m; i++)
36 {
37 int a = p[i].u;
38 int b = p[i].v;
39 if (find(a) == find(b))
40 {
41 cout << p[i].w << endl;
42 return 0;
43 }
44 else
45 {
46 if (!e[a])
47 {
48 e[a] = b;
49 }
50 else
51 {
52 merge(e[a], b);
53 }
54 if (!e[b])
55 {
56 e[b] = a;
57 }
58 else
59 {
60 merge(e[b], a);
61 }
62 }
63 }
64 cout << 0 << endl;
65 return 0;
66 }
特殊的并查集:
1 #include<iostream>
2 #include<cstring>
3 #include<algorithm>
4 #include<cstdio>
5 using namespace std;
6 const int maxn = 100010;
7 int n, m;
8 int ans;
9 int f[maxn * 3];
10 void init()
11 {
12 for (int i = 1; i <= n * 3; i++)
13 f[i] = i;
14 }
15 int find(int x)
16 {
17 return f[x] == x ? x : f[x] = find(f[x]);
18 }
19 void merge(int a, int b)
20 {
21 int x = find(a);
22 int y = find(b);
23 if (x != y)
24 f[y] = x;
25 }
26 int main()
27 {
28 cin >> n >> m;
29 init();
30 for(int i=1;i<=m;i++)
31 {
32 int t, x, y;
33 cin >> t >> x >> y;
34 if (x > n || y > n)
35 {
36 ans++;
37 continue;
38 }
39 if (t == 1)
40 {
41 if (find(x) == find(y + n) || find(x + n) == find(y))
42 {
43 ans++;
44 }
45 else
46 {
47 merge(x, y);
48 merge(x + n, y + n);
49 merge(x + 2 * n, y + 2 * n);
50 }
51 }
52 else
53 {
54 if (find(x) == find(y) || find(x) == find(y + n))
55 {
56 ans++;
57 }
58 else
59 {
60 merge(x + n, y);
61 merge(x + 2 * n, y + n);
62 merge(x, y + 2 * n);
63 }
64 }
65 }
66 cout << ans << endl;
67 return 0;
68 }