E - 食物链 POJ - 1182 -带权并查集

本文介绍了一种使用并查集数据结构处理复杂食物链关系的方法,通过递归查找和路径压缩技巧,实现了对动物间同类关系和捕食关系的有效判断。详细解析了算法流程,包括冲突检测和关系传递的特殊规律。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • E - 食物链

  •  POJ - 1182 
  • 中文题意:第一种说法是"1 X Y",表示X和Y是同类。 第二种说法是"2 X Y",表示X吃Y。 
  • 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。
  • 当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
  • 1) 当前的话与前面的某些真的话冲突,就是假话; 
  • 2) 当前的话中X或Y比N大,就是假话; 
  • 3) 当前的话表示X吃X,就是假话。 
  • 思路:并查集的处理思路,统一与根节点建立联系方便查询,路径压缩过程有所改变,如果本身是根节点
  • 那么无需处理直接返回,如果需要往上查询则记录下当前u的父亲节temp点然后进行递归直到根节点开始更新回溯
  • 更新u——>根节点的关系时:
  • num[u].val=(num[u].val+num[temp].val)%3

  • 然后先更新不断回溯即可
  • 这里的取余是根据题目的情况特殊规律,把关系看做指向根节点的向量,把(0-同类)(1-被根吃)(2-吃根节点)
  • 看做之间的关系可以发现 进行关系传递是是满足向量加法的,但是不能超出这三种情况需要对三进行取余
  • #include<iostream>
    #include<stdio.h>
    using namespace std;
    #define maxn 50555
    struct node
    {
        int fa,val;
    } num[maxn];
    int root (int u)
    {
        if(u==num[u].fa)
            return u;
        int temp=num[u].fa;
        num[u].fa=root(temp);
        num[u].val=(num[u].val+num[temp].val)%3;
        return num[u].fa;
    }
    int n,q,ans,op,u,v,fu,fv;
    int main()
    {
        scanf("%d%d",&n,&q);
        ans=0;
        for(int i=1; i<=n; i++)
        {
            num[i].fa=i;
            num[i].val=0;
        }
        while(q--)
        {
            scanf("%d%d%d",&op,&u,&v);
            if(u>n||v>n)
            {
                ans++;
                continue;
            }
            if(op==2&&u==v)
            {
                ans++;
                continue;
            }
            fu=root(u);
            fv=root(v);
            if(op==1)
            {
                if(fu==fv)
                {
                    if(num[u].val!=num[v].val)
                        ans++;
                }
                else if(fu!=fv)
                {
                    num[fv].fa=fu;
                    num[fv].val=(3-num[v].val+num[u].val)%3;
                }
            }
            else if(op==2)
            {
                if(fu==fv)
                {
                    if((num[v].val+3-num[u].val)%3!=1)
                        ans++;
                }
                else if(fu!=fv)
                {
                    num[fv].fa=fu;
                    num[fv].val=(3-num[v].val+num[u].val+1)%3;
                }
            }
        }
        printf("%d\n",ans);
        return 0;
    }
  •  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值