/* [NOI2001] 食物链*/
//
//#include<cstdio>
//#include<cstring>
//#include<iostream>
//#include<algorithm>
//#include<queue>
//using namespace std;
//const int maxn = 1e5 + 10;
//int a, b, p, ans = 0, n, m;
//int fa[maxn], group[maxn];
加权并查集,子节,种类并查集group,group[x]表示x的父亲与x的关系.
并查集的两个操作,合并与查询,两者都要考虑对父亲的影响.
//
//
//int find(int x) {//查询并压缩路径
// int ff = fa[x];//x的父亲
// if (ff != x) {//如果x不是祖宗,即需要查找x的祖宗是谁
// fa[x] = find(ff);//找到x的祖宗直接赋值作为x的父亲,压缩路径同时改变权值
// group[x] = (group[x] + group[ff]) % 3;//为压缩路径,改变与父亲关系为与父亲的父亲的关系即同时要改变权值,\
// //因为group为0,1,2.即子与父,父与祖的关系可的子与祖的关系 可分类为00=0,01=1,02=2,10=1,11=2(因为是abc三个族群是循环的)
// //12=0,20=2,21=0,22=1;
// return fa[x];
// }
// else return x;
//}
//
//
//int main()
//{
// cin >> n >> m;
// for (int i = 1; i <= n; i++) fa[i] = i, group[i] = 0;//group 0为同类,子与父亲的关系0--> 同种动物,1-- > 捕食关系,
// //2-- > 被捕食关系,初始化全部为0;因为开始是父节点全是自己,即都是祖宗节点,group[祖宗节点]=0;
// for (int i = 0; i < m; i++) {
// cin >> p >> a >> b;
// if (a > n || b > n || (p == 2 && a == b)) {//简单错误
// ans++;
// continue;
// }
// if (p == 1) {//如果是同盟的情况
// int faa = find(a), fbb = find(b);//查找父节点
// if (faa == fbb && group[a] != group[b]) {//如果祖宗节点是一个,那么在两个动物是同盟的情况下,两者的捕食关
// ans++;//系应该是相同的否则错误
// continue;
// }
// else if (faa != fbb) {//如果两者捕食一个祖宗那么将两个并查集合并
// fa[faa] = fbb; group[faa] = (group[b] - group[a] + 3) % 3;//合并时让a的祖宗作为b的祖宗的儿子,而且需要更
//
// //新两者的关系由ab是同盟以及a和祖宗的关系,与b与祖宗的关系推出a祖与b祖的关系
// }
// }
// if (p == 2) {//如果为捕食关系
// int faa = find(a), fbb = find(b);
// if (faa == fbb) {//同一祖宗
// int x = (group[a] - group[b] + 3) % 3; //用两个节点与父亲的关系推出两者关系应该是什么
// if (x != 1) {//如果不对
// ans++;
// continue;
// }
//
// }
// else {//不是统一祖宗即两个并查集则一定正确
// fa[faa] = fbb;
// group[faa] = (3 - group[a] + group[b] + 1) % 3; //合并
// }
// }
// }
// cout << ans << endl;
// return 0;
//}
[并查集] P2024 [NOI2001] 食物链
于 2022-01-14 11:27:02 首次发布