poj 1182 食物链

http://poj.org/problem?id=1182


思路为带权并查集,定义数组relation[i]表示i与fa[i]的关系:

  • relation[i]=0,i和fa[i]是同类。
  • relation[i]=1,fa[i]吃i。
  • relation[i]=1,i吃fa[i]。

初始化:fa[i]=i,relation[i]=0。

更新:每次把fa[i]改成父亲的父亲,relation[i]=(relation[i]+relation[fa[i]])%3。注意每次更新i时,i的父亲都以更新完毕,所以root只会是i的父亲或爷爷。

判断:为了方便,传入的relation为d-1。

  • 如果x和y的根节点相同,说明在同一集合内,那么:

    (r[y]-r[x]+3)%3==relation,则为真,反之则为假(可以通过列举得到规律)。

  • 如果x和y根节点不同,则说明此前x和y没有关系,表达式一定是正确的,就把两个集合相结合起来即可。
    组合过程:把rooty的父亲改为y,把y的父亲改为x,把rooty的父亲改成rootx。


#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
const int N=50005;

int fa[N];
int r[N];//relationip。0同类,1被父亲吃,2吃父亲

int find(int x)
{
    if(x!=fa[x])
    {
        int root=find(fa[x]);
        r[x] = (r[x]+r[fa[x]])%3;//在这里更新x的时候,x的父亲已经更新完毕,root只会为x的父亲或是爷爷。
        fa[x] = root;
    }
    return fa[x];
}


int Judge(int relation, int x, int y)
{
    int rootx=find(x);
    int rooty=find(y);
    if(rootx!=rooty)
    {
        fa[rooty] = y;
        r[rooty] = (3-r[y])%3;//根据rooty对y的关系逆推出y对rooty的关系
        fa[y] = x;
        r[y] = relation;//relation就是x对y的关系
        return 0;//新的关系一定是正确的
    }
    else if ((r[y]-r[x]+3)%3==relation)
        return 0;
    else return 1;
}

int main()
{
    int ans = 0;
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1; i<=n; i++)
    {
        fa[i] = i;
        r[i] = 0;
    }
    while(k--)
    {
        int d,x,y;
        scanf("%d%d%d",&d,&x,&y);
        if(x>n || y>n || (d==2 && x==y))
            ans++;
        else
            ans += Judge(d-1,x,y);//relation的值为d-1
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值