POJ 1182 食物链(加权并查集)

思路:如果比较两动物之间的关系的话,肯定需要判断一下是否有关系,然后又有什么关系,这个有什么关系的话可以用一个r[]数组表示。

如果两动物有关系k==1&&r[a]!=r[b]一定是假话,k==2,那么r[a]的级别一定是r[b]之前即(r[a]+1)%3==r[b],否则是假话。

如果两者没关系,那么去创建并查集f[]和r[]. 一、要合并首先要查找两者祖先,同时在查找祖先,将经过的节点值回溯给f[x],同时更新r[x],r[x]是在回溯的时候从更早的祖先一点的回退到较晚的祖先,所以我们可以将一个更早祖先的值记录,r[x]=(r[x]+r[t])%3,(t为更早祖先的值)。 二、完成合并,在进行节点的合并时,注意将两种动物合成一到固定的树上,同时更新r[],那么在两棵树进行合并的时候又怎么更新r[]呢?

感谢图片制作者

(这里的x,y,是程序中的a,b;fx,fy是x,y;)
前提我们可以定义三种关系 a b同及为0,a倍b吃为2,b倍a吃为1.

我们可以画出一个正方形
a b

x y 最终我们要x->y所以依次y->bb->aa->xx->y知道他们的关系。a->x,为r[a].

#include<map>
#include<queue>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
#define LL __int64
#define inf 0x3f3f3f3f
const double PI=acos(-1.0);
using namespace std;
int f[1000000],r[1000000];
int fi(int x){
    if(x==f[x])
        return x;
    int t;
    t = f[x];
    f[x]=fi(f[x]);
    r[x] = (r[x] + r[t] )%3;
    return f[x];
}

void mer(int a,int b,int k){
    int x=fi(a);
    int y=fi(b);
    f[y]=x;
    r[y]=(r[a]-r[b]+k-1+3)%3;
}

int main(){
    int n,m,i,j,k,a,b,ans;
   scanf("%d%d",&n,&m);
        ans=0;
        for(i=1;i<=n;++i){
            f[i]=i;
            r[i]=0;
        }
        for(i=1;i<=m;++i){
            scanf("%d%d%d",&k,&a,&b);
            if(a>n||b>n||(k==2&&a==b)){
                ans++;continue;
            }

            if(fi(a)==fi(b)){
                if( k==1&&r[a]!=r[b] ) ans++;
                else if(k==2&&(r[a]+1)%3!=r[b] ) ans++;
            }
            else{
                mer(a,b,k);
            }
        }
        printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值