题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66964#problem/E
题意:求假话的数量。
怎么说呢?题目就是会了不难,难的不会!!在网上了看了N多题解,绝大多数都是用一个什么公式来更新的,感觉那个真的不太适合我,说以也就没管了。偶然在白神的一本上看到了此题的另一种解法,可以说是通俗易懂,nice!上正文:
思路:维护每一个动物的三种关系:自己同类的,吃自己的,被自己吃的。如果用三个数组来来维护,即:A表示同类,B表示被自己吃的,C表示吃自己的,那么这样一来,就不能用同一个pre数组来维护了,因为A[i],B[i],C[i]这三个集合的意义是不一样的,但是pre[i] 却只有一种意思。怎么办呢?其实很简单,为了解决pre的重复问题,我们开一个三倍于N一维数组就行了。其中1~N表示同类,N+1~N+N表示1~N对应的动物所吃,2N+1~2N+N表示吃1~N对应的动物,这样一来,我们就可以用一个pre数组来维护三者之间的关系了。
此题还得注意的是:只有一组数据输入,否则会WA。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100010
using namespace std;
int pre[maxn*3];
int N,K;
int find(int x){
int t=x;
while(pre[t]!=t) t=pre[t];
while(x!=t) pre[x]=t,x=pre[x];
return t;
}
int judge(int a,int b,int c){
if(a==2 && b==c) {return 0;}
if(b>N || c>N) {return 0;}
int fb=find(b),fc=find(c);
if(a==1){
if(fb==find(c+N) || fb==find(c+2*N)){ return 0;}
pre[fb]=fc;
pre[find(b+N)]=find(c+N);
pre[find(b+2*N)]=find(c+2*N);
return 1;
}
if(fb==fc || fb==find(c+N)) {return 0;}
pre[fb]=find(c+2*N);
pre[find(b+N)]=fc;
pre[find(b+2*N)]=find(c+N);
return 1;
}
int main(){
//freopen("D:in.txt","r",stdin);
cin>>N>>K;
int a,b,c,ans=0;
for(int i=0;i<=3*N;i++) pre[i]=i;
for(int i=0;i<K;i++){
scanf("%d %d %d",&a,&b,&c);
if(judge(a,b,c)) continue;
ans++;
}
cout<<ans<<endl;
return 0;
}