很好的并查集问题。
题目不是很难理解 : 有3类动物,对于每一类动物分别存在它的猎物、天敌、与同类。不难看出我们需要开三个并查集去存储每一只动物的猎物、天敌、与同类。
处理每一次遇到的话:
首先判断它是关于同类的叙述还是天敌的叙述,对于这次所涉及的动物X与Y:
1、同类:首先判断Y存不存在于X天敌或者是猎物的并查集中,如果两者都不存在,那么一定是同类了,说明当前的声明的是真话,并进行将Y合并到X同类的并查集中、X合并到Y同类的并查集中的操作;否则当前的声明的是假话,ans++,并跳过所有操作。
2、Y是X的猎物:首先判断Y存不存在于X天敌或者同类的并查集中,如果两者都不在的话,Y一定是X的猎物了,说明当前的声明是真话,并进行将Y合并到X猎物的并查集中、X合并到Y天敌的并查集中的操作;否则说明当前的声明是假话,ans++,并跳过所有操作。
直观感受一下:
其实只用开一个并查集,这个并查集不同的区间代表不同的类别(猎物、天敌、与同类),如上图。
OK & AC。
代码:
#include <bits/stdc++.h>
const int N = 500000 + 5 ;
int f [ N ] , n , k , ans , ok , Y , X ;
int find ( int x ) {
return f [ x ] == x ? x : ( find ( f [ x ] ) ) ;
}
int main ( ) {
scanf ( "%d%d" , & n , & k ) ;
for ( int i = 1 ; i <= 3 * n ; i ++ ) f [ i ] = i ;
for ( int i = 1 ; i <= k ; i ++ ) {
scanf ( "%d%d%d" , & ok , & X , & Y ) ;
if ( X > n || Y > n ) { ans ++ ; continue ; }
if ( ok == 1 ) {
if ( find ( X + n ) == find ( Y ) || find ( X + 2 * n ) == find ( Y ) )
ans ++ ;
else {
f [ find ( X ) ] = find ( Y ) ;
f [ find ( X + n ) ] = find ( Y + n ) ;
f [ find ( X + 2 * n ) ] = find ( Y + 2 * n ) ;
}
}
else {
if ( X == Y ) { ans ++ ; continue ; }
if ( find ( X ) == find ( Y ) || find ( X + 2 * n ) == find ( Y ) )
ans ++ ;
else {
f [ find ( X + 2 * n ) ] = find ( Y + n ) ;
f [ find ( X + n ) ] = find ( Y ) ;
f [ find ( X ) ] = find ( Y + 2 * n ) ;
}
}
}
printf ( "%d" , ans ) ;
return 0 ;
}