思路:
看起来并查集似乎不太好下手, 但如果我们拆成几个属性以后就方便合并了
开三倍n大小的数组, x代表x的种族, x + n代表x的猎物, x + 2 * n代表x的天敌(这里的 猎物/天敌 不仅仅是个体, 而是一个群体)
如果操作为1 x y的话, 我们就将x跟y合并, x + n跟y + n合并, x + 2 * n跟y + 2 * n合并(同类属性相同)
如果操作为2 x y的话, 我们就将
x跟y + 2 * n合并(x是y的天敌),
x + n跟y合并(x的猎物是y),
x + 2 * n跟y + n合并(x的天敌是y的猎物, 因为根据题意中的描述, 食物链是一个环, A吃B, B吃C, C吃A)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <string> 6 #include <bitset> 7 #include <vector> 8 #include <map> 9 #include <queue> 10 using namespace std; 11 typedef long long ll; 12 13 const int MAXN = 5e4 + 7, INF = 0x3f3f3f3f; 14 int fa[4 * MAXN], ra[4 * MAXN], n, m, cnt; 15 16 inline ll read() 17 { 18 19 int x = 0, f = 1; 20 char ch = getchar(); 21 while (ch < '0' || ch > '9') 22 { 23 if (ch == '-') 24 f = -1; 25 ch = getchar(); 26 } 27 while (ch >= '0' && ch <= '9') 28 { 29 x = x * 10 + ch - '0'; 30 ch = getchar(); 31 } 32 return x * f; 33 } 34 35 int find(int x) 36 { 37 return x == fa[x] ? x : fa[x] = find(fa[x]); 38 } 39 bool unite(int x, int y) 40 { 41 x = find(x); 42 y = find(y); 43 if (x == y) 44 return false; 45 if (ra[x] > ra[y]) 46 swap(x, y); 47 48 fa[y] = x; 49 if (ra[x] == ra[y]) 50 ra[x]++; 51 return true; 52 } 53 54 int main() 55 { 56 int ans = 0; 57 int T, x, y, op; 58 59 n = read(); 60 m = read(); 61 cnt = n; 62 for (int i = 1; i <= 3 * n; ++i) 63 { 64 fa[i] = i; 65 ra[i] = 1; 66 } 67 68 for (int i = 0; i < m; ++i) 69 { 70 op = read(); 71 x = read(); 72 y = read(); 73 if (x > n || y > n) 74 { 75 ++ans; 76 continue; 77 } 78 if (op == 1) 79 { 80 if (find(x) == find(y + 2 * n) || find(x + 2 * n) == find(y)) 81 { 82 ans++; 83 continue; 84 } 85 unite(x, y); 86 unite(x + n, y + n); 87 unite(x + 2 * n, y + 2 * n); 88 } 89 else 90 { 91 if (find(x) == find(y) || find(2 * n + x) == find(y)) 92 { 93 ans++; 94 continue; 95 } 96 unite(x, y + 2 * n); 97 unite(x + n, y); 98 unite(x + 2 * n, y + n); 99 } 100 } 101 printf("%d ", ans); 102 103 return 0; 104 }