poj食物链,经典带权并查集

题目描述

动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A 吃 B,B

吃 C,C 吃 A。

现有 N 个动物,以 1 - N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道

它到底是哪一种。

有人用两种说法对这 N 个动物所构成的食物链关系进行描述:

第一种说法是“1 X Y”,表示 X 和 Y 是同类。

第二种说法是“2 X Y”,表示 X 吃 Y 。

此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真

的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

• 当前的话与前面的某些真的话冲突,就是假话

• 当前的话中 X 或 Y 比 N 大,就是假话

• 当前的话表示 X 吃 X,就是假话

你的任务是根据给定的 N 和 K 句话,输出假话的总数。

 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
 const int maxn=1e5+10;
int fa[maxn],rnk[maxn];//rnk点与根的关系
int n,k;
void init(int x){
    for(int a=0;a<=x;a++){
        fa[a]=a;
        rnk[a]=0;
    }
}
int findfa(int x){
   if(fa[x]==x)
       return x;
   else{
       int mid=fa[x];
       fa[x]=findfa(fa[x]);//压缩
       rnk[x]=(rnk[x]+rnk[mid])%3;//节点与根的关系     rnk[mid]是mid与根结点的关系
       return fa[x];//第二个rnk[x]是当前的点到压缩前的根的关系,rnk【mid】是之前的根到当前的根的关系,两者相加即为当前的点到当前的根的关系
   }
}
void merge(int r,int x,int y){
    int fx=findfa(x);
    int fy=findfa(y);
    if(fx!=fy){
        fa[fx]=fy;
        rnk[fx]=(rnk[y]-rnk[x]+r+3)%3;
    }
}
bool check(int a,int b,int c){
    if (b>n||c>n||b<1||c<1) {
        return false;
    }
    if(a==1&&b==c)
        return false;
    int fb=findfa(b);
    int fc=findfa(c);
    if(fb==fc)
        return  a==(rnk[b]-rnk[c]%3+3)%3;
    else
        return true;
}
int main()
{
    int ans = 0;
    scanf("%d %d",&n,&k);
    init(n);
    for (int a=0; a<k; a++) {
        int o,p,q;
        cin>>o>>p>>q;
        o--;
        if(check(o,p,q))
            merge(o,p,q);
        else
            ans++;
    }
    printf("%d\n",ans);
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值