[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;
}
原文地址:https://www.cnblogs.com/virtual-north-Illya/p/10045395.html