天天看點

poj1182食物鍊(三類并查集)includeinclude

動物王國中有三類動物A,B,C,這三類動物的食物鍊構成了有趣的環形。A吃B, B吃C,C吃A。

現有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

第一行是兩個整數N和K,以一個空格分隔。

以下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

AC代碼:

include

include

using namespace std;

const int maxn=50000+50;

int a[3*maxn+1],s,N;

int find(int b){

if(a[b]==b) return b;

else return a[b]=find(a[b]);

}

/int find(int b){

while(b!=a[b]){

b=a[b];

}

return b;

}/

void unite(int b,int c){

int x=find(b),y=find(c);

a[y]=x;

}

void diff(int b,int c){

int x=find(b),y=find(c),y1=find(c+2N);

if(x==y||x==y1||b==c) s++;

else {

unite(b,c+N);

unite(b+N,c+2N);

unite(b+2N,c);

}

}

void init(){

for(int i=1;i<=3N+10;i++)

a[i]=i;

}

void same(int b,int c){

int x=find(a[b]),x1=find(a[c+2*N]),y1=find(a[c+N]);

if(x==y1||x==x1) s++;

else{

unite(b,c);

unite(b+N,c+N);

unite(b+2N,c+2N);

}

}

int main(){

int K;

cin>>N>>K;

s=0;

init();

while(K--){

int a,b,c;

scanf("%d%d%d",&a,&b,&c);

if(b>N||c>N||c<1||b<1) {

s++;

continue;

}

if(a==1) same(b,c);

else diff(b,c);

// printf("%d %d\n",s,K);

}

printf("%d\n",s);

return 0;

}

注釋:a[x]表示x在A中,a[x+N]表示x在B中,a[x+2*N]表示x在C中,将一種情況分成三種情況

轉載于:https://www.cnblogs.com/sunjianzhao/p/11414529.html