1. 程式人生 > 其它 >【並查集】食物鏈

【並查集】食物鏈

題目描述

動物王國中有三類動物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和K句話,輸出假話的總數。

【輸入格式】

第一行是兩個整數N和K,以一個空格分隔。

以下K行每行是三個正整數D,X,Y,兩數之間用一個空格隔開,其中D表示說法的種類。

D=1,則表示X和Y是同類。

D=2,則表示X吃Y。

【輸出格式】

只有一個整數,表示假話的數目。

【資料範圍】

1≤N≤50000,
0≤K≤100000

【輸入樣例】

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

【輸出樣例】

3

使用並查集,維護一下每個點之間的距離即可。

一個並查集一共有三類動物,用0、1、2表示,定義a->b表示b吃a,假定0->2,2->1,1->0,用與根節點之間的距離模3表示三種不同型別的動物,需要注意的是距離有可能在維護過程中變為負數,因此在計算的時候需要注意表示式的書寫。

 1 #include <iostream>
 2 using namespace std;
 3 const int N = 50009;
 4 int p[N],d[N];
 5 int n,k;
 6 
 7 int find(int x)
 8 {
 9     if(p[x] != x)
10     {
11         int u = find(p[x]);
12         d[x] += d[p[x]];
13         p[x] = u;
14     }
15     return p[x];
16 }
17 
18 int main()
19 {
20 cin >> n >> k; 21 for(int i = 1;i <= n;++i) 22 p[i] = i; 23 int res = 0; 24 while(k--) 25 { 26 int op,a,b; 27 cin >> op >> a >> b; 28 if(a > n || b > n) 29 ++res; 30 else if(op == 1) 31 { 32 int pa = find(a),pb = find(b); 33 if(pa == pb && (d[b] - d[a]) % 3) 34 ++res; 35 if(pa != pb) 36 { 37 p[pa] = pb; 38 d[pa] = d[b] - d[a]; 39 } 40 } 41 else 42 { 43 if(a == b) 44 { 45 ++res; 46 continue; 47 } 48 int pa = find(a),pb = find(b); 49 if(pa == pb && (d[a] - d[b] - 1) % 3) 50 ++res; 51 if(pa != pb) 52 { 53 p[pa] = pb; 54 d[pa] = d[b] - d[a] + 1; 55 } 56 } 57 } 58 cout << res << endl; 59 return 0; 60 }