【NOI2001】食物链

【NOI2001】食物链

题意

动物王国中有三类动物 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 句话有的是真
的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
• 当前的话与前面的某些真的话冲突,就是假话
• 当前的话中 X 或 Y 比 N 大,就是假话
• 当前的话表示 X 吃 X,就是假话
你的任务是根据给定的 N 和 K 句话,输出假话的总数。

解法

  1. 我们开三个并查集,分别表示这个动物 本身 食物 天敌,然后每次合并时,判断一下是否违法,并将对应的关系合并,就可以统计出假话的个数了。
  2. 我们利用权值并查集,用 $ kind[ i ] $表示 i 与他的父亲的关系。
    0 表示他与他的父亲是同类。
    1 表示他被他的父亲吃。
    2 表示他吃他的父亲。
    然后我们要获取父亲与他的关系,就用 $ ( 3 - kind[ i ] ) $就行了。更新关系就用 $ kind[i] = (kind[fa]+kind[i]) \mod 3 $。

    代码

    第一类
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=(5e4+10)*3;
int fa[maxn];
int _find(int x) {
    return fa[x]==x ? x : fa[x]=_find(fa[x]);
} 
void uni(int x,int y) {
    int f1=_find(x),f2=_find(y);
    if(f1!=f2) fa[f2]=f1;
}

int n,k;
int main()
{
    read(n),read(k);
    for(int i=1;i<=3*n;i++) fa[i]=i;// x本身 ,x+n食物 ,x+2*n天敌 
    int tot=0;
    for(int i=1;i<=k;i++) {
        int c,x,y;
        read(c),read(x),read(y);
        if(x>n || y>n) {++tot;continue;}
        if(c==1) {
            if(_find(x+n)==_find(y) || _find(x+2*n)==_find(y)) ++tot;
            else {
                uni(x,y),uni(x+n,y+n),uni(x+2*n,y+2*n);
            }
        }
        else {
            if(x==y) {++tot;continue;}
            if(_find(x)==_find(y) || _find(x+2*n)==_find(y)) ++tot;
            else {
                uni(x+n,y),uni(x,y+2*n),uni(x+2*n,y+n);
            }
        }
    }
    printf("%d",tot);
    return 0;
}

第二类

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=5e4+10;
int fa[maxn],kind[maxn];
int _find(int x) {
    int f=fa[x];
    if(f!=x) {
        fa[x]=_find(fa[x]);
        kind[x]=(kind[x]+kind[f])%3;
    }
    return fa[x];
} 
int n,k;
int main()
{
    read(n),read(k);
    for(int i=1;i<=n;i++) fa[i]=i;
    int tot=0;
    for(int i=1;i<=k;i++) {
        int c,x,y;
        read(c),read(x),read(y);
        if(x>n || y>n || (c==2&&x==y)) {++tot;continue;}
        if(c==1) {
            int f1=_find(x),f2=_find(y);
            if(f1==f2) {if(kind[x]!=kind[y]) ++tot;}
            else fa[f2]=f1,kind[f2]=(3-kind[y]+kind[x])%3;
        }
        else {
            int f1=_find(x),f2=_find(y);
            if(f1==f2) {if((kind[x]-kind[y]+3)%3!=2) ++tot;}
            else fa[f2]=f1,kind[f2]=(4-kind[y]+kind[x])%3;
        }
    }
    printf("%d",tot);
    return 0;
}

转载于:https://www.cnblogs.com/mrasd/p/9550153.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值