洛谷 P2024 [NOI2001]食物链 并查集变形 读入优化

题目链接:

https://www.luogu.com.cn/problem/P2024

参考博客:

https://www.luogu.com.cn/blog/DanKuroto/solution-p2024

这个博客真心太牛逼了,讲的清晰透彻,真心棒,建议复习时一定要看

算法:

并查集

思路:

1:就是用3倍的并查积的存各种动物的关系,一倍存本身,二倍存猎物,三倍存天敌,特别特别注意:一的猎物的猎物 就是一的天敌

2:每次维护三个并查积的关系

#include <bits/stdc++.h>

using namespace std;
const int maxn=3e5+3;
int fa[maxn],n,k,ans,x,y,z;

inline int read()//读入优化
{
    int sum=0;
    char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();
    return sum;
}

int  find(int x)//查根
{
    if(x!=fa[x])fa[x]=find(fa[x]);
    return fa[x];
}

void unity(int x,int y)//合并
{
    int r1=find(fa[x]),r2=find(fa[y]);
    fa[r1]=r2;
}

int main()
{
    ios::sync_with_stdio(0);
    n=read(),k=read();
    for(int i=1;i<=3*n;i++)fa[i]=i;//对于每种生物:设 x 为本身,x+n 为猎物,x+2*n 为天敌
    for(int i=1;i<=k;i++)
    {
        z=read(),x=read(),y=read();
        if(x>n||y>n){   ans++;continue;}// 不属于该食物链显然为假
        if(z==1)
        {
            if(find(x+n)==find(y)||find(x+2*n)==find(y)){ans++;continue;}
            //如果1是2的天敌或猎物,显然为谎言
            unity(x,y);unity(x+n,y+n);unity(x+2*n,y+2*n);
            //如果为真,1,2为同类,1的猎物和2的猎物也为同类,1的天敌和2的天敌也为同类
        }
        else if(z==2)
        {
            if(x==y){ans++;continue;}
            if(find(x)==find(y)||find(x+2*n)==find(y)){ans++;continue;}
            //如果1是2的同类或猎物,显然为谎言,只有1是2的天敌才正确
            unity(x,y+2*n);unity(x+n,y);unity(x+2*n,y+n);
            //如果为真,那么1的同类是2的天敌,1的猎物是2的同类,1的天敌是2的猎物
        }
    }
    printf("%d\n",ans);
    return 0;
}
发布了117 篇原创文章 · 获赞 37 · 访问量 6569

猜你喜欢

转载自blog.csdn.net/aiwo1376301646/article/details/104209599