题意

存在一个环形食物链,即a->b->c->a,给出m条语句,均为两个动物是同一种,或者a吃b,问有多少句是假的,先入为主,若两句冲突,第一句为真。

题解

使用并查集。
以每个动物自身等级为基准,设定所有其他动物的等级,具体表现就是:开n*3的数组,a代表a所在等级,a+n代表吃a的等级,a+n+n代表被a吃的等级。
将语句中同一等级的动物放到同一个集合中,比如,1吃2,则将1+n(被a吃的等级)和b放到同一集合来设定a与b在食物链中关系。
那么判断两动物a,b是否在同一等级,就只需看a+n与b,a+n+n与b是否在一个集合中。
判断两动物是否为a吃b的关系,就只需看a与b,a与b+n+n是否在同一集合中。

Code

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5e4 + 10;
int fa[maxn * 3];                   //记录祖先节点

int fi(int x){                  //find函数寻找祖先
    return x == fa[x] ? x : fa[x] = fi(fa[x]);
}

void un(int x,int y){           //union函数建立两点关系
    int p = fi(x);
    int q = fi(y);
    if(p != q) fa[p] = q;
}

int main(){     //若a吃b,则a的等级与b+n等级相同
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=3*n;i++) fa[i]=i;
    int cnt = 0;
    while(m--){
        int op,a,b;                     
        scanf("%d%d%d",&op,&a,&b);
        if(a<1||a>n||b<1||b>n) {        //数据范围错误
            cnt++; 
            continue;
        }
        if(op==2&&a==b){                //表示x吃x
            cnt++;
            continue;
        }
        if(op==1){                      
            if(fi(a)==fi(b+n)||fi(a)==fi(b+n+n)) cnt++; //若a和b不为同一种
            else {
                un(a,b);                                //将a,b设置为同一等级
                un(a+n,b+n);
                un(a+n+n,b+n+n);
            }
        }
        else if(op == 2){                              
            if(fi(a)==fi(b)||fi(a)==fi(b+n+n)) cnt++;
            else {
                un(a,b+n);                             //令a与b+1为同一等级
                un(a+n,b+n+n);
                un(a+n+n,b);
            }
        }
    }
    printf("%d\n",cnt);
    return 0;
}