食物链题解(并查集)

在这里插入图片描述
在这里插入图片描述
食物链
首先可知 A 吃 B,B 吃 C,C 吃 A。故知道A和B,B和C的关系,便可推出A和C的关系。
主要思想
维护一个集合,若两动物已经在集合中,便可判断其关系是否正确,若不在集合中,便可加入集合。那么怎么判断当前加入的动物是A,B,C中的哪类动物呢?可以用一个距离数组记录(假设为d),那么d[i]为动物i到根节点的距离,将其%3即d[i]%3即可判断他是哪类动物(假设1吃0,2吃1,0吃2)并且不断维护这个数组即可。
那么并查集find的模板代码为

int find(int x)    //p[x]为并查集,d[x]为距离
{
    if(p[x]!=x)
    {
        int t=find(p[x]);         //首先记录下p[x]的祖先
        d[x]+=d[p[x]];        //更新距离
        p[x]=t;
    }
    return p[x];
}

在这里插入图片描述
主要代码

while(k--)
    {
        int m,x,y;
        scanf("%d%d%d",&m,&x,&y);
        
        if(x>n||y>n) 
        {
            res++;
            continue;
        }
        
        int px=find(x),py=find(y);
        if(m==1)
        {
            if(px==py&&(d[x]-d[y])%3) res++;   //当已经在集合当中,并且为同类时
            								如果(d[x]-d[y])%3!=0那么假话数加一		
            else if(px!=py)
            {
                p[px]=py;
                d[px]=d[y]-d[x];       //祖先的距离计算如下图,不需要改变d[x],因为在find函数中                      
             }                                 会动态维护d[x]的值。
        }
        else
        {
            if(px==py&&(d[x]-d[y]-1)%3) res++;
            else if(px!=py)
            {
                p[px]=py;
                d[px]=d[y]-d[x]+1;    //同理
            }
        }
}

在这里插入图片描述
全部代码

#include<iostream>
#include<algorithm>

using namespace std;

const int N=50010;

int p[N];
int d[N];
int n,k;

int find(int x)
{
    if(p[x]!=x)
    {
        int t=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=t;
    }
    return p[x];
}
int main()
{
    cin>>n>>k;
    
    for(int i=1;i<=n;i++) p[i]=i;
    
    int res=0;
    while(k--)
    {
        int m,x,y;
        scanf("%d%d%d",&m,&x,&y);
        
        if(x>n||y>n) 
        {
            res++;
            continue;
        }
        
        int px=find(x),py=find(y);
        if(m==1)
        {
            if(px==py&&(d[x]-d[y])%3) res++;
            else if(px!=py)
            {
                p[px]=py;
                d[px]=d[y]-d[x];
            }
        }
        else
        {
            if(px==py&&(d[x]-d[y]-1)%3) res++;
            else if(px!=py)
            {
                p[px]=py;
                d[px]=d[y]-d[x]+1;
            }
        }
    }
    
    cout<<res<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值