[并查集] P2024 [NOI2001] 食物链

/*    [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;
//}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值