題目:
食物鏈
Time Limit: 1000MS
Memory Limit: 65536KB
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句話有的是真的,有的是假的。當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。
1) 當前的話與前面的某些真的話衝突,就是假話;
2) 當前的話中X或Y比N大,就是假話;
3) 當前的話表示X喫X,就是假話。
你的任務是根據給定的N(1 <= N <= 50,000)和K句話(0 <= K <= 100,000),輸出假話的總數。
Input
第一行是兩個整數N和K,以一個空格分隔。
以下K行每行是三個正整數 D,X,Y,兩數之間用一個空格隔開,其中D表示說法的種類。
若D=1,則表示X和Y是同類。
若D=2,則表示X喫Y。
Output
只有一個整數,表示假話的數目。
Sample Input
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
Sample Output
3
代碼:
#include <cstdio>
#include <cstring>
const int MAXN = 5e4 + 10;
int set[3*MAXN];//主要建立三個集合分別表示:同類,x喫y(喫),y喫x(被喫)
int find(int p)
{
if(set[p] < 0) return p;
return set[p] = find(set[p]);
}
void join(int p, int q)
{
p = find(p), q = find(q);
if(p != q) set[p] = q;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
memset(set, -1, sizeof(set));
int d, x, y, cnt = 0;
while(m--)
{
scanf("%d%d%d", &d, &x, &y);
if(x>n || y>n || (2==d && x==y))
{
cnt++; continue;
}
if(x == y) continue;
switch(d)
{
case 1:
{
if(find(x+n)==find(y) || find(x+2*n)==find(y) ||
find(x)==find(y+n) || find(x)==find(y+2*n))
{
cnt++; continue;
}
join(x, y);
join(x+n, y+n);
join(x+2*n, y+2*n);
break;
}
case 2:
{
if(find(x)==find(y) || find(x+2*n)==find(y) ||
find(x)== find(y+n))
{
cnt++; continue;
}
join(x, y+2*n);
join(x+n, y);
join(x+2*n, y+n);
break;
}
}
}
printf("%d\n", cnt);
return 0;
}