P2024 [NOI2001] 食物链 总结
P2024 [NOI2001] 食物链
思路
我们设
其实就是上面所说的:如果
我们就需要建立关系,可是我们如果改一次,就从头更新到脚趾尖,那么显然超时,所以我们充分发扬人类智慧,将线段树里的
直接加上关系即可,因为反正是要加上的,然后要用路径压缩,由于
最后考虑如何合并,我们知道两个集合的合并,其实是两个集合的根的合并,但是
那么可以的到关系式:
即:
这个时候就可得到两集合合并时的
code
#include <iostream>
using namespace std;
const int MaxN = 5e4 + 10;
int fa[MaxN], c[MaxN], n, k, ans;
int Ff(int x) {
if (fa[x] < 0)
return x;
int root = Ff(fa[x]);
c[x] = (c[x] + c[fa[x]]) % 3;
return fa[x] = root;
}
void Merge(int x, int y, int f) {
int fx = Ff(x), fy = Ff(y);
c[fy] = (f - c[y] + c[x] + 6) % 3, fa[fy] = fx;
}
int main() {
//freopen("tmp.in", "r", stdin);
//freopen("tmp.out", "w", stdout);
cin >> n >> k;
fill(fa + 1, fa + n + 1, -1);
for (int i = 1, op, x, y; i <= k; i++) {
cin >> op >> x >> y;
if (x > n || y > n) {
ans++;
continue;
}
if (op == 1) {
if (Ff(x) != Ff(y)) {
Merge(x, y, 0);
} else if (c[x] != c[y]) {
ans++;
}
} else {
if (Ff(x) != Ff(y)) {
Merge(x, y, 1);
} else if ((c[y] - 1 + 3) % 3 != c[x]) {
ans++;
}
}
}
cout << ans << endl;
return 0;
}
总结
首先是要构造出种类规则,然后转换成 并查集 的语言,然后利用线段树的