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;
}