CF559E Gerald and Path
阿新 • • 發佈:2022-02-05
我們定義:對於任意一個 \(i\):
- \(i\) 表示其本身。
- \(n + i\) 表示 \(i\) 的天敵。
- \(2n + i\) 表示 \(i\) 的獵物。
(您可能不知道定義是最難想的)
題目中對於假話的定義是:
- 當前的話與前面的某些真的話衝突,就是假話;
- 當前的話中 X 或 Y 比 N 大,就是假話;
- 當前的話表示 X 吃 X,就是假話。
其中,第 \(2\)、\(3\) 條容易判斷(直接特判),那第 \(1\) 條呢?
首先宣告一下,只有真話才會被錄入資訊。
- 如果 \(x\) 和 \(y\) 是同類,若 \(x\) 是 \(y\) 的天敵或獵物,那麼是假話。
- 如果 \(x\) 吃 \(y\),若 \(x\) 和 \(y\) 是同類,那麼是假話。
- 如果 \(x\) 吃 \(y\),若 \(x\) 是 \(y\) 的獵物,那麼是假話。
- 如果 \(x\) 吃 \(y\),若 \(y\) 是 \(x\) 的天敵,那麼是假話。
關於 \(i\) 的天敵和獵物,我們已經有所定義。
所以,到這裡,應該很容易看出來是並查集。
看出來是並查集,就很容易做了。
若您不會並查集,請移步至 AcWing 836. 合併集合。
最後注意:合併時也有些講究。(自己想想啊呀,待會看程式碼)
Code:
#include <iostream> #include <cstdio> using namespace std; int n, k, ans = 0; int fa[150010]; //注意陣列開 3 倍。 int find (int x) { if(fa[x] != x) return fa[x] = find(fa[x]); return fa[x]; } int main() { scanf("%d%d", &n, &k); for (int i = 1; i <= 3 * n; i ++ ) fa[i] = i; //基本初始化。 while (k -- ) { int op, x, y; scanf("%d%d%d", &op, &x, &y); if(x > n || y > n) { ans ++; continue; } if(op == 1) { if(find(x) == find(y + n)) { ans ++; continue; } if(find(x) == find(y + 2 * n)) { ans ++; continue; } fa[find(y)] = find(x); fa[find(y + n)] = find(x + n); fa[find(y + 2 * n)] = find(x + 2 * n); } if(op == 2) { if(x == y) { ans ++; continue; } if(find(x) == find(y)) { ans ++; continue; } if(find(x) == find(y + 2 * n)) { ans ++; continue; } fa[find(x)] = find(y + n); fa[find(y)] = find(x + 2 * n); fa[find(x + n)] = find(y + 2 * n); } } printf("%d", ans); return 0; }
若您覺得有幫助,就點個贊吧。
更多精彩請關注我的部落格號~
祝各位 rp++ !