[NOI2001]食物链

[NOI2001]食物链

这题我采用的是并查集扩展域做法,当然还有边带权的做法,但我还不会.

我们发现,所有的动物相对于每一种动物都能划分出三个集合 (:) 同类集合,食物集合,天敌集合.

所以,把每一种动物进行扩展域,用三个并查集维护.

每次读进一个同类就判断其中一个是否在另一个的食物集合,天敌集合中即可.

如果矛盾,就统计答案,否则就把两个动物的三个集合一一合并,因为显然同类的天敌和食物都一样.

读进一个 (x)(y) 的捕食操作呢?

判断是否存在我吃你而你吃我的情况,这显然是矛盾的.

另一种矛盾的情况是它们已经是同类了,直接查询即可.

如果不矛盾,就合并 (x) 的同类集合和 (y) 的天敌集合, (x) 的食物集合和 (y) 的同类集合, (x) 的食物集合和 (y) 的食物集合.

因为既然 (x)(y) 那么 (x) 的同类显然都吃 (y) ,并且 (y) 的同类显然都是 (x) 的食物,根据题意还可以知道 (y) 的食物也是 (x) 的食物.

于是这题就做完了.

扩展域也算是并查集的套路,见过一次基本就会了.

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#define MEM(x,y) memset ( x , y , sizeof ( x ) )
#define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
#define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
#define pii pair < int , int >
#define one first
#define two second
#define rint read<int>
#define pb push_back
#define db double
#define ull unsigned long long
#define lowbit(x) ( x & ( - x ) )

using std::queue ;
using std::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::swap ;
using std::sort ;
using std::unique ;
using std::greater ;

template < class T >
    inline T read () {
        T x = 0 , f = 1 ; char ch = getchar () ;
        while ( ch < '0' || ch > '9' ) {
            if ( ch == '-' ) f = - 1 ;
            ch = getchar () ;
        }
       while ( ch >= '0' && ch <= '9' ) {
            x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
            ch = getchar () ;
       }
       return f * x ;
    }

const int N = 5e4 + 100 ;

int n , k , f[N*3] , ans ; // i is self , i + n is enemy , i + 2n is eaten ones.

inline int getf (int x) { return f[x] == x ? x : f[x] = getf ( f[x] ) ; }

inline void merge (int x , int y) {
    x = getf ( x ) ; y = getf ( y ) ;
    if ( x != y ) f[y] = x ; return ;
}

int main (int argc , char * argv[]) {
    n = rint () ; k = rint () ;
    rep ( i , 1 , n * 3 ) f[i] = i ;
    while ( k -- ) {
        int opt = rint () , u = rint () , v = rint () ;
        if ( u < 1 || u > n || v < 1 || v > n ) { ++ ans ; continue ; }
        if ( opt == 1 ) {
            int tx = getf ( u ) , ty = getf ( v ) ;
            if ( tx == getf ( v + n ) || tx == getf ( v + 2 * n ) ) { ++ ans ; continue ; }
            if ( ty == getf ( u + n ) || ty == getf ( u + 2 * n ) ) { ++ ans ; continue ; }
            merge ( u , v ) ; merge ( u + n , v + n ) ; merge ( u + 2 * n , v + 2 * n ) ;
        } else {
            if ( u == v ) { ++ ans ; continue ; }
            int tx = getf ( u ) , ty = getf ( v ) ;
            if ( tx == ty ) { ++ ans ; continue ; }
            if ( getf ( u + n ) == ty ) { ++ ans ; continue ; }
            if ( tx == getf ( v + 2 * n ) ) { ++ ans ; continue ; }
            merge ( u , v + n ) ; merge ( u + 2 * n , v ) ; merge ( u + n , v + 2 * n ) ;
        }
    }
    printf ("%d
" , ans ) ;
    #ifndef ONLINE_JUDGE
    system ("pause") ;
    #endif
    return 0 ;
}
原文地址:https://www.cnblogs.com/Equinox-Flower/p/11773780.html