zoukankan      html  css  js  c++  java
  • [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*104,1≤K≤105。


    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
    ",cnt);
    	return 0;
    }
    
  • 相关阅读:
    树状数组
    LCA最近公共祖先
    ordered_set
    马拉车算法
    数论
    图论
    其他
    线段树
    序列自动机
    优先队列
  • 原文地址:https://www.cnblogs.com/virtual-north-Illya/p/10045395.html
Copyright © 2011-2022 走看看