五行学说
题意
五行金木水火土中有“生”和“克”的关系,关系如下
共有 s a b 代表 k a b 代表
算法
并查集,带权并查集
带权并查集
在并查集原有树的基础上,给每个树的边一个权值,可用一个数组 fa[N] 表示这个点的祖先,用 v[N] 表示这个点到其父亲的边的边权
核心思路
处理多个数的关系时,我们通常会用并查集,对于克和生的关系,我们可以使用带权并查集来完成,我们用边权为
关键
在同一个集合中如何判断两个元素的关系呢?只需要求出两者之间的距离就可以!
当处理没有在同一个集合的元素时,如何将两个集合合并呢?传统集合只需要 fa[x]=y 而带边权的集合却需要将其中的 v[x] 更新,我们已知
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, ans, fa[N], v[N];
int find(int x) {
if (fa[x] == x) return x;
int t = find(fa[x]);
v[x] = (v[fa[x]] + v[x]) % 5;
fa[x] = t;
return t;
}
int main() {
for (int i = 1; i < N; i++) fa[i] = i;
cin >> n >> m;
char c;
int a, b;
for (int i = 1; i <= m; i++) {
cin >> c >> a >> b;
int x = find(a), y = find(b);
if (x == y) {
int d = (v[a] - v[b] + 10) % 5;
if ((c == 'k' && d != 2) || (c == 's' && d != 1)) ans++;
} else {
fa[x] = y;
int d = (c == 'k' ? 2 : 1);
v[x] = (-v[a] + d + v[b] + 10) % 5;
}
}
cout << ans << endl;
return 0;
}