Skip to content

Commit 25b15ce

Browse files
committed
[AcWing Base course] DSA/UnionFind
1 parent 897ad74 commit 25b15ce

File tree

4 files changed

+276
-0
lines changed

4 files changed

+276
-0
lines changed

DSA/UnionFind/AW240.cpp

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
AcWing
3+
240. 食物链
4+
https://www.acwing.com/problem/content/242/
5+
6+
if x and y are in same set(px == py), we can determine their relation by d.
7+
d[i] record the distance from i to the root of the set tree
8+
(distance of the food chain, not the set tree height)
9+
- if (d[x] - d[y]) % 3 == 0, same kind
10+
- if ((d[x] - d[y]) % 3 + 3) % 3 == 1, x eat y
11+
12+
if x and y not in the same set (px != py), we need to merge two set tree:
13+
- p[px] = py: set father of px to be py
14+
- determine the 'd' of px
15+
- if x, y are same kind:
16+
d[px] = d[y] - d[x]
17+
because x and y are same kind, so
18+
- d[x] -> d[y],
19+
- d[px] -> new d[x] - old d[x] = d[y] - d[x]
20+
- if x eat y:
21+
we need to insert x under y, so
22+
- d[x] -> d[y] + 1
23+
- d[px] -> new d[x] - old d[x] = d[y] + 1 - d[x]
24+
we only need to update d of px, because when we update d of px,
25+
the followings under px will be auto update by the call of find()
26+
27+
because union-find set need to flatten the set tree,
28+
so we need to update the d of each node when calling find()
29+
*/
30+
#include <bits/stdc++.h>
31+
using namespace std;
32+
33+
const int N = 5e4 + 10;
34+
const int K = 1e5 + 10;
35+
36+
int n, k;
37+
int cnt;
38+
39+
int p[N], d[N];
40+
41+
int find(int x) {
42+
if(p[x] != x) {
43+
int t = find(p[x]);
44+
d[x] += d[p[x]]; /* old p[x] */
45+
p[x] = t;
46+
}
47+
return p[x];
48+
}
49+
50+
int main() {
51+
cin >> n >> k;
52+
for(int i = 1; i <= n; i++) {
53+
p[i] = i;
54+
}
55+
while(k--) {
56+
int D, x, y;
57+
cin >> D >> x >> y;
58+
if(x > n or y > n) {
59+
cnt++;
60+
continue;
61+
}
62+
int px = find(x), py = find(y);
63+
64+
if(D == 1) {
65+
/* say x, y 同类 */
66+
if(px == py) { /* smae set, can determin relation */
67+
if((d[x] - d[y]) % 3 != 0) {
68+
cnt++;
69+
continue;
70+
}
71+
} else {
72+
p[px] = py; /* merge px to py */
73+
d[px] = d[y] - d[x]; /* same class */
74+
}
75+
76+
} else if(D == 2) {
77+
/* say x eat y */
78+
if(x == y) {
79+
cnt++;
80+
continue;
81+
}
82+
if(px == py) {
83+
/* in same set, known the relation */
84+
// if((d[x] - d[y] - 1) % 3)
85+
if(((d[x] - d[y]) % 3 + 3) % 3 != 1) {
86+
cnt++;
87+
continue;
88+
}
89+
} else {
90+
/* not int samse set, merge and build relation (d) */
91+
/* actrualy, we insert x under y,
92+
** so the d of px = d[y] + 1 - d[x] */
93+
p[px] = py; /* merge px to py */
94+
d[px] = d[y] + 1 - d[x];
95+
}
96+
} else {
97+
assert(false);
98+
}
99+
}
100+
cout << cnt << endl;
101+
}
102+
/*
103+
输入样例:
104+
100 7
105+
1 101 1
106+
2 1 2
107+
2 2 3
108+
2 3 3
109+
1 1 3
110+
2 3 1
111+
1 5 5
112+
输出样例:
113+
3
114+
*/

DSA/UnionFind/AW240_noted.cpp

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
作者:yxc
3+
链接:https://www.acwing.com/activity/content/code/content/45325/
4+
来源:AcWing
5+
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6+
*/
7+
8+
#include <iostream>
9+
10+
using namespace std;
11+
12+
const int N = 1e5 + 10;
13+
14+
int n, m;
15+
int p[N], d[N]; // p[]寻找祖宗节点,d[]求到祖宗节点的距离
16+
17+
int find(int x) {
18+
if(p[x] != x) {
19+
int t = find(p[x]); // u暂时存一下p[x]根节点,辅助变量
20+
d[x] += d[p[x]]; // 更新距离
21+
p[x] = t;
22+
}
23+
return p[x];
24+
}
25+
26+
// 不行,因为这个路径的长度(高度),是需要自上而下加起来的,从根节点往下走
27+
// 所以要先调用递归
28+
29+
// int find(int x)
30+
// {
31+
// if (p[x] != x)
32+
// {
33+
// d[x] += d[p[x]]; // 更新距离
34+
// p[x] = find(p[x]);
35+
// }
36+
// return p[x];
37+
// }
38+
39+
int main() {
40+
scanf("%d%d", &n, &m);
41+
42+
for(int i = 1; i <= n; i++)
43+
p[i] = i;
44+
45+
int res = 0; // 记录错误数
46+
while(m--) {
47+
int t, x, y;
48+
scanf("%d%d%d", &t, &x, &y);
49+
50+
if(x > n || y > n)
51+
res++; // 当前的话中X或Y比N大,是假话
52+
else {
53+
int px = find(x), py = find(y); // 查找根节点
54+
if(t == 1) {
55+
// 判断是否同类
56+
if(px == py) { // 若 x 与 y 在同一个集合中
57+
if((d[x] - d[y]) % 3)
58+
res++;
59+
// 两数到根节点距离之差的模不为
60+
// 0,说明不是同一类,是假话
61+
// 其中 (d[x] - d[y]) % 3 不可写为 d[x] % 3 != d[y] % 3
62+
// 因为 d[x], d[y] 可能为负数(一正一负),可改做 (d[x] % 3
63+
// + 3) % 3 != (d[y] % 3 + 3) % 3 负数 mod 正数为负数
64+
} else { // 则 x 与 y 不在同一个集合中
65+
p[px] = py; // x 所在集合 合并到 y 所在集合
66+
d[px] = d[y] - d[x];
67+
// d[x] 的距离为什么不更新?
68+
// 只是暂时不更新,在调用 find 时再更新
69+
}
70+
} else {
71+
// X 是否吃 Y
72+
if(px == py) {
73+
// 若 x 与 y 在同一个集合中
74+
// 若 X 吃 Y,则 d[x] 比 d[y] 大 1
75+
if((d[x] - d[y] - 1) % 3)
76+
res++;
77+
// 若距离之差 - 1 的模不为 0,说明吃不掉,是假话
78+
} else {
79+
// 则 x 与 y 不在同一个集合中
80+
p[px] = py; /* 合并集合 */
81+
// (d[x] - d[y] - 1) % 3 == 0
82+
// d[x] + d[px] - 1 = d[y] 则:
83+
d[px] = d[y] + 1 - d[x];
84+
}
85+
}
86+
}
87+
}
88+
89+
printf("%d\n", res);
90+
91+
return 0;
92+
}

DSA/UnionFind/AW837.cpp

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
AcWing 837. 连通块中点的数量
3+
https://www.acwing.com/problem/content/839/
4+
输入样例:
5+
5 5
6+
C 1 2
7+
Q1 1 2
8+
Q2 1
9+
C 2 5
10+
Q2 5
11+
输出样例:
12+
Yes
13+
2
14+
3
15+
*/
16+
#include <bits/stdc++.h>
17+
using namespace std;
18+
const int N = 1e5 + 10;
19+
int n, m;
20+
int p[N], cnt[N];
21+
22+
int find(int x) {
23+
if(p[x] != x) {
24+
p[x] = find(p[x]);
25+
}
26+
return p[x];
27+
}
28+
29+
int main() {
30+
cin >> n >> m;
31+
for(int i = 1; i <= n; i++) {
32+
p[i] = i;
33+
cnt[i] = 1;
34+
}
35+
string op;
36+
int a, b;
37+
while(m--) {
38+
cin >> op;
39+
if(op == "C") {
40+
cin >> a >> b;
41+
int pa = find(a), pb = find(b);
42+
if(pa != pb) {
43+
p[pa] = pb;
44+
cnt[pb] += cnt[pa];
45+
}
46+
} else if(op == "Q1") {
47+
cin >> a >> b;
48+
int pa = find(a), pb = find(b);
49+
if(pa == pb) {
50+
cout << "Yes" << endl;
51+
} else {
52+
cout << "No" << endl;
53+
}
54+
} else if(op == "Q2") {
55+
cin >> a;
56+
int pa = find(a);
57+
cout << cnt[pa] << endl;
58+
}
59+
}
60+
}

Math/testmod.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
int main() {
5+
cout << (-2) % 3 << endl;
6+
cout << (-3) % 3 << endl;
7+
cout << (6) % 3 << endl; /* 0 */
8+
cout << (-1) % 3 << endl;
9+
cout << (-2) % 3 << endl;
10+
}

0 commit comments

Comments
 (0)