地址 https://www.papamelon.com/problem/241
有 N 只動物, 分別編號爲 1,2,3...,N。
所有動物都屬於 A,B,C 中的一種。已知
A 喫 B、
B 喫 C、
C 喫 A。
按順序給出下面的兩種信息共
K 條:
第一種:
1 x y 表示 ,x,y 屬於同一種類
第二種:
2 x y 表示 x 喫 y
這些信息有可能會出錯。和之前已給出的信息矛盾, 也有的信息可能給出的 x 和 y 不在1,2,3...,N 的範圍內。
求在 K 條信息中有多少條是不正確的。
先出現的信息被認爲是正確的。後出現的信息如果和前面的矛盾,則被認爲是錯誤的。
輸入
第一行包含兩個整數 N 和 K
接下來的
K 行,每行有三個整數
t x y,分別表示信息的類型(1≤t≤2)以及 x 和 y
1≤N≤50000,0≤K≤100000
輸出
一個整數,表示有多少條不正確的信息
樣例 1
輸入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
輸出
3
解答
並查集擴展域的好題
給出的動物 xy一定在ABC之中,等價於動物關係要麼是同類要麼是天敵(A喫B 或者B喫A)
那麼判斷 ab a+N b+N a+2N b+2N是否在同一個並查集裏 就能判斷話的真僞了。
#include <iostream>
using namespace std;
const int N = 50010;
int f[N * 3]; // n~a 2n~a的食物 3n~a的天敵
//並查集 初始化
void init() {
for (int i = 0; i < N * 3; i++) {
f[i] = i;
}
}
//並查集查找
int find(int x) {
if (f[x] != x) {
f[x] = find(f[x]);
}
return f[x];
}
//並查集合並
void merge(int a, int b) {
a = find(a); b = find(b);
if (a < b) {
f[b] = a;
}
else {
f[a] = b;
}
}
int n, k;
int main()
{
cin >> n >> k;
int ans = 0;
init();
for (int i = 0; i < k; i++) {
int d, a, b;
cin >> d >> a >> b;
//如果動物編號超過限制 假話
if (a > n || b > n ) {
ans++; continue;
}
else if(d == 1) {
//ab同類的語句
a = find(a); b = find(b);
//判斷a和b是同類的情況下 a能和b的食物天敵在同一個集合中 有衝突 假話
if (a == find(b + n) || a == find(b + 2 * n) ) {
ans++;
}
else {
//真話 合併它們的關係 還要合併他們的天敵和食物的關係
merge(a, b); merge(a+n, b+n); merge(a+2*n, b+2*n);
}
}
else if (d == 2) {
//a喫b 也就是 b是a的食物 的語句
a = find(a); b = find(b);
//a喫b 如果還有a和b同類或者 a是b的食物 ,衝突判斷爲假話
if (a == b || a == find(b + n)) {
ans++;
}
else {
//不衝突 合併它們的關係 a是b的天敵 a的食物是b的同類 a的天敵是b的食物
merge(a + n, b); merge(a + 2 * n, b + n); merge(a,b+2*n);
}
}
}
cout << ans << endl;
return 0;
}