【题解】食物链

题目链接

我来补博客例题了……

对于本题,我们维护不同物种之间的关系。设有动物A,B,则必有:

1.A>B

2.A=b

3.A<B.

所以,对于三种关系,我们都需要维护。

不妨,我们开三倍大小的并查集,其中,1~n是A种群,n+1~2n是B种群,2n+1~3n是C种群,并设有:

A>B,B>C,C>A.

每一种动物,在A,B,C种群中都有。设它们的目的,后面再说。

首先,对于A,B,如果它们是同一物种,那么,我们就需要把三个种群中的A和B全部merge.以此表示它们和平。

那么,对于A>B(即A吃B)呢?

从前文知,我们有3个群体,它们之间有捕食与被捕食的关系。那么,我们让A群中的A与B群中的Bmerge,B群中的A与C群中的Bmerge,C群中的A与A群中的Bmerge.

由于集群中互斥,以此维护其关系。

那么,考虑如何判断假话。

首先,对于A=B,则必有A与B互相不大于。即,A不吃B,B不吃A。那么,我们只要判断,A的当前集群的A与B的下一个集群的B是否在同一集合,或是B集群的B与A的下一个集群的A是否在同一集群内。如果符合上述条件,即假话。

否则,三个集合中的A与B全部合并。

那么,对于A>B呢(B>A)

首先,它们不能是同类,判断它们本身是否在一个集合即可。

其次,它们不能互相克制。即,A>B,B不能>A.

并查集显而易见了。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
inline int read(){
    char ch=getchar();int s=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){
        s=(s<<1)+(s<<3)+(ch^48);
        ch=getchar();
    }return s;
}
const int MAXN=100010;
int n,m,ans,f[MAXN+(MAXN<<1)];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
int main(){
    //freopen("P2024.in","r",stdin);
    //freopen("P2024.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=(n+(n<<1));++i)f[i]=i;
    for(;m;m--){
        int opt=read(),u=read(),v=read();
        if(u>n||v>n){ans++;continue;}
        if(opt==1){
            if(find(u+n)==find(v)||find(u)==find(v+n))ans++;
            else{
                f[find(u)]=find(v);
                f[find(u+n)]=find(v+n);
                f[find(u+(n<<1))]=find(v+(n<<1));
            }
        }else{
            if(find(u)==find(v)||find(u)==find(v+n))ans++;
            else{
                f[find(u+n)]=find(v);
                f[find(u+(n<<1))]=find(v+n);
                f[find(u)]=find(v+(n<<1));
            }
        }
    }
    printf("%d
",ans);
    //fclose(stdin);
    //fclose(stdout);
    return 0;
} 
View Code

其实,这道并查集与前面的并查集是有区别的,一者维护路径信息,一者维护多种关系。

原文地址:https://www.cnblogs.com/h-lka/p/11164229.html