Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 66720 | Accepted: 19675 |
Description
現有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
以下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
/*
* poj 1182
* author : mazciwong
* creat on: 2016-1-18
*/
/*
按A,B,C分類,並查集解決
並查集是維護 "屬於同一組"的數據結構
因爲有真有假,所有N個元素每個都可以分到三組中去
所以設出來的並查集有三個根,這三個是劃分塊,不能同時成立
每個劃分塊裏面是等價類,一個成立則其他都成立
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 150000 + 5;
int n, k;
int d, x, y;
int fa[maxn];
int depth[maxn];
//maxn是最多的節點數,init中的n是用到的
//並查集初始化
void init(int n)
{
//包括用rank記錄樹的高度和路徑壓縮兩種優化
for (int i = 0; i < n; i++)
{
fa[i] = i;
depth[i] = 0;
}
}
//並查集查詢
int find(int x)
{
if (x == fa[x])
return x;
else
return fa[x] = find(fa[x]);
}
//並查集合並
void unite(int x, int y)
{
x = find(x);
y = find(y);
if (x == y) return;
if (depth[x] < depth[y]) //x根更短,則x指向y
fa[x] = y;
else if(depth[x]>depth[y])
fa[y] = x;
else //一樣高的話,誰指向誰都可以,記得高度加一
{
fa[y] = x;
depth[x]++;
}
}
//判斷是否屬於同一個集合
bool same(int x, int y)
{
return find(x) == find(y);
}
/*
n個元素,每個元素都能放入A.B.C中,則共3n種對應法
用並查集來分組,在一組的話同時成立,相當於等價劃分塊
*/
void solve()
{
int ans = 0;
for (int i = 0; i < k; i++)
{
scanf("%d%d%d", &d, &x, &y);
x--, y--;//把他們從1-n變成從0-(n-1),方便計算
//題目裏給出的第二種錯誤
if (x < 0 || x >= n || y < 0 || y >= n)
{
ans++;
continue;
}
//下面是循環讀入,然後並查集處理
if (d == 1) //x,y同一類
{
//就不能跟另外兩個同類了
if (same(x, y + n) || same(x, y + 2 * n))
ans++;
else
{ //要三個都寫是因爲後面兩個一定成立,x在A,y在A,那麼當x在B,y一定在B
unite(x, y);
unite(x + n, y + n);
unite(x + 2 * n, y + 2 * n);
}
}
else //x喫y
{
if (same(x, y) || same(x, y + 2 * n))
ans++;
else
{
unite(x, y + n);
unite(x + n, y + 2 * n);
unite(x + 2 * n, y);
}
}
}
printf("%d\n", ans);
}
int main()
{
scanf("%d%d", &n, &k);
init(n * 3);//把3*n種配對都初始化出來
solve();
return 0;
}