【洛谷】 NOI 2024 食物链

很好的并查集问题。

 

题目不是很难理解 : 有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 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值