[NOI2001]食物链 洛谷P2024

Description

动物王国中有三类动物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句话,输出假话的总数。


Input

第一行两个整数N,K,表示有N个动物,K句话。第二行开始每行一句话。

Output

一行,一个整数,表示假话的总数。

Hint

1≤N≤5*10^4,1≤K≤10^5。

Solution

种类并查集,详见注释。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 100005
using namespace std;
int FA[maxn],rel[maxn];
int n,k,x,y,z,cnt;
/*
0 x和父亲是同类
1 x吃父亲
2 x被父亲吃 
*/
int dofind(int x){
    if(FA[x]==x)return x;
    int fa=FA[x],rx=dofind(FA[x]);
    if(rel[x]==0){
        if(rel[fa]==0){//如果x和fa是同类并且fa的父亲是同类,那么x和fa的父亲是同类 
            rel[x]=0;
        }
        else if(rel[fa]==1){//fa吃它父亲,那么x也吃fa的父亲
            rel[x]=1;
        }
        else if(rel[fa]==2){//fa被它父亲吃,那么x也被它父亲吃 
            rel[x]=2;
        }
    }
    else{
        if(rel[x]==1){
            if(rel[fa]==0){//如果x吃fa并且fa和它父亲是同类,x吃它父亲 
                rel[x]=1;
            }
            else if(rel[fa]==1){//如果fa吃它父亲,x就被它父亲吃 
                rel[x]=2;
            }
            else if(rel[fa]==2){//如果fa被它父亲吃,x和它父亲就是同类 
                rel[x]=0;
            }
        }
        else if(rel[x]==2){
            if(rel[fa]==0){//如果x被fa吃并且fa和它父亲是同类,x被它父亲吃 
                rel[x]=2;
            }
            else if(rel[fa]==1){//fa吃它父亲,x和它父亲就是同类 
                rel[x]=0;
            }
            else if(rel[fa]==2){//fa被它父亲吃,x就吃它父亲 
                rel[x]=1;
            }
        }
    }
    return FA[x]=rx;
}
bool dofinD(int x,int y){
    return dofind(x)==dofind(y);
}
void dounion(int x,int y,int meg){
    if(dofinD(x,y)){
        if(rel[x]==1&&rel[y]==1){//如果x吃fa并且y也吃fa,如果meg不等于1就是假话 
            if(meg!=1){
                cnt++;
            }
            return;
        }
        else if(rel[x]==1&&rel[y]==0){//如果x吃fa并且y和fa是同类,如果meg不等于2就是假话 
            if(meg!=2){
                cnt++;
            }
            return;
        }
        else if(rel[x]==1&&rel[y]==2){//如果x吃fa并且y被fa吃,无论如何都是假话 
            cnt++;
            return;
        }
        else if(rel[x]==0&&rel[y]==0){//如果x和fa是同类并且y和fa是同类,如果meg不等于1就是假话 
            if(meg!=1){
                cnt++;
            }
            return;
        }
        else if(rel[x]==0&&rel[y]==1){//如果x和fa是同类并且y吃fa,无论如何都是假话 
            cnt++;
            return;
        }
        else if(rel[x]==0&&rel[y]==2){//如果x和fa是同类并且y被fa吃,如果meg不等于2就是假话 
            if(meg!=2){
                cnt++;
            }
            return;
        }
        else if(rel[x]==2&&rel[y]==0){//如果x被fa吃并且y和fa是同类,无论如何都是假话 
            cnt++;
            return;
        }
        else if(rel[x]==2&&rel[y]==1){//如果x被fa吃并且y吃fa,如果meg不等于2就是假话 
            if(meg!=2){
                cnt++;
            }
            return;
        }
        else if(rel[x]==2&&rel[y]==2){//如果x被fa吃并且y也被fa吃,如果meg不等于1的话就是假话 
            if(meg!=1){
                cnt++;
            }
            return;
        }
    }
    else{
        int dx=dofind(x),dy=dofind(y);
        FA[dx]=FA[dy];
        if(rel[x]==0){
            if(meg==1){//如果x和dx是同类并且y和x是同类 
                if(rel[y]==0){//如果y和dy是同类,dx和dy也是同类 
                    rel[dx]=0;
                }
                else if(rel[y]==1){//如果y吃dy,dx也吃dy 
                    rel[dx]=1;
                }
                else if(rel[y]==2){//如果y被dy吃,dx也被dy吃 
                    rel[dx]=2;
                }
            }
            else if(meg==2){//如果x吃y 
                if(rel[y]==0){//如果y和dy是同类,dx吃dy 
                    rel[dx]=1;
                }
                else if(rel[y]==1){//如果y吃dy,dx被dy吃 
                    rel[dx]=2;
                }
                else if(rel[y]==2){//如果y被dy吃,dx和dy就是同类 
                    rel[dx]=0;
                }
            }
        }
        else if(rel[x]==1){
            if(meg==1){//如果x吃dx并且x和y是同类 
                if(rel[y]==0){//如果y和dy是同类,dx就被dy吃 
                    rel[dx]=2;
                }
                else if(rel[y]==1){//如果y吃dy,dx和dy是同类 
                    rel[dx]=0;
                }
                else if(rel[y]==2){//如果y被dy吃,dx吃dy 
                    rel[dx]=1;
                }
            }
            else if(meg==2){//如果x吃y 
                if(rel[y]==0){//如果y和dy是同类,dx和dy是同类 
                    rel[dx]=0;
                }
                else if(rel[y]==1){//如果y吃dy,dx也吃dy 
                    rel[dx]=1;
                }
                else if(rel[y]==2){//如果y被dy吃,dx也被dy吃 
                    rel[dx]=2;
                }
            }
        }
        else if(rel[x]==2){
            if(meg==1){//如果x被dx吃并且x和y是同类 
                if(rel[y]==0){//如果y和dy是同类,dx也要吃dy 
                    rel[dx]=1;
                }
                else if(rel[y]==1){//如果y吃dy,那么dy要吃dx 
                    rel[dx]=2;
                }
                else if(rel[y]==2){//如果y被dx吃,那么dy和dx是同类 
                    rel[dx]=0;
                }
            }
            else if(meg==2){//如果x吃y 
                if(rel[y]==0){//如果y和dy是同类,dy吃dx 
                    rel[dx]=2;
                }
                else if(rel[y]==1){//如果y吃dy,dx和dy是同类 
                    rel[dx]=0;
                }
                else if(rel[y]==2){//如果y被dy吃,dx吃dy 
                    rel[dx]=1;
                }
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        FA[i]=i;
    }
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&x,&y,&z);
        if(y>n||z>n){
            cnt++;
            continue;
        }
        dounion(y,z,x);
    }
    printf("%d\n",cnt);
    return 0;
}

转载于:https://www.cnblogs.com/virtual-north-Illya/p/10045395.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值