題目大意:動(dòng)物王國(guó)中有三類動(dòng)物A,B,C,這三類動(dòng)物的食物鏈構(gòu)成了有趣的環(huán)形。A吃B, B吃C,C吃A。
現(xiàn)有N個(gè)動(dòng)物,以1-N編號(hào)。每個(gè)動(dòng)物都是A,B,C中的一種,但是我們并不知道它到底是哪一種。
有人用兩種說法對(duì)這N個(gè)動(dòng)物所構(gòu)成的食物鏈關(guān)系進(jìn)行描述:
第一種說法是"1 X Y",表示X和Y是同類。
第二種說法是"2 X Y",表示X吃Y。
此人對(duì)N個(gè)動(dòng)物,用上述兩種說法,一句接一句地說出K句話,這K句話有的是真的,有的是假的。當(dāng)一句話滿足下列三條之一時(shí),這句話就是假話,否則就是真話。
1) 當(dāng)前的話與前面的某些真的話沖突,就是假話;
2) 當(dāng)前的話中X或Y比N大,就是假話;
3) 當(dāng)前的話表示X吃X,就是假話。
你的任務(wù)是根據(jù)給定的N(1 <= N <= 50,000)和K句話(0 <= K <= 100,000),輸出假話的總數(shù)。
題目分析;由于N和K很大,所以必須高效的維護(hù)動(dòng)物之間的關(guān)系,并快速判斷是否殘生了矛盾,所以決定采用并查集。
對(duì)于每只動(dòng)物i創(chuàng)建3個(gè)元素i,i+N,i+2N,并用這3*N個(gè)元素創(chuàng)建并查集。這個(gè)并查集維護(hù)如下信息:
i+xN表示“i屬于種類x”。
并查集里的每一個(gè)組表示組內(nèi)所有元素代表的都同時(shí)發(fā)生或不發(fā)生。
同時(shí),在合并之前先判斷合并是否會(huì)產(chǎn)生矛盾。
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = 50050;
int father[maxn*3], n, m, ans;
void init() {
for(int i=0;i<3*n;i++) father[i] = i;
}
int find(int x) {
return x == father[x] ? x : father[x] = find(father[x]);
}
void unite(int x, int y) {
int a = find(x) , b = find(y);
father[a] = father[b] = father[x] = father[y] = min(a, b);
}
bool check(int d, int x, int y) {
if(x >= n || y >= n || x < 0 || y < 0)
return false;
if(d == 2 && x == y)
return false;
if(d == 1) {
if(find(x) == find(y+n) || find(x) == find(y+2*n))
return false;
unite(x, y);
unite(x+n, y+n);
unite(x+2*n, y+2*n);
return true;
} else {
if(find(x) == find(y) || find(x) == find(y+2*n))
return false;
unite(x, y+n);
unite(x+n, y+2*n);
unite(x+2*n, y);
return true;
}
}
int main() {
scanf("%d%d" , &n, &m);
init();
ans = 0;
for(int i=0;i<m;i++) {
int d, x, y;
scanf("%d%d%d", &d, &x, &y);
x --; y --;
if(check(d, x, y) == false)
ans ++;
}
printf("%d\n", ans);
return 0;
}
posted on 2015-02-11 17:33
JulyRina 閱讀(287)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
解題報(bào)告