1182 食物链


//1182 食物链 利用向量偏移的并查集
//
//每个集合都有三类动物,用rank表示,0——同类;1——食物;2——天敌,初始时都以自己为根节点,且rank为0
//只需对每一句话,判断x,y是否同一集合内,如果是就判断语句真假,否则就合并集合
//根据公式知道x-y=d-1,主要想出几个推导公式:
//1:  rank[x]=(rank[x]+rank[temp])%3    
//     这个最好设一两个例子验证一下,由于每次都是两集合的根合并,且只有根更改rank,所以每个x的rank值只会与
//     它的father有关(只有一次father更改,就是跟合并时),然后结合向量偏移得到。
//  比如a-b = 1 b-c = 1 那么a-c等于2
//三个公式都与向量偏移计算得来,看下面的详解
//附1:
//向量偏移解说
/*
> 什么叫做向量的思维模式?
> Orz Orz
我的理解是,对于集合里的任意两个元素a,b而言,它们之间必定存在着某种联系,


因为并查集中的元素均是有联系的,否则也不会被合并到当前集合中。那么我们


就把这2个元素之间的关系量转化为一个偏移量,以食物链的关系而言,不妨假设


a->b 偏移量0时 a和b同类


a->b 偏移量1时 a吃b


a->b 偏移量2时 a被b吃,也就是b吃a


有了这些基础,我们就可以在并查集中完成任意两个元素之间的关系转换了。


不妨继续假设,a的当前集合根节点aa,b的当前集合根节点bb,a->b的偏移值为d-1(题中给出的询问已知条件)


(1)如果aa和bb不相同,那么我们把bb合并到aa上,并且更新delta[bb]值(delta[i]表示i的当前集合根节点到i的偏移量)


此时 aa->bb = aa->a + a->b + b->bb,可能这一步就是所谓向量思维模式吧


上式进一步转化为:aa->bb = (delta[a]+d-1+3-delta[b])%3 = delta[bb],(模3是保证偏移量取值始终在[0,2]间)


(2)如果aa和bb相同,那么我们就验证a->b之间的偏移量是否与题中给出的d-1一致


此时 a->b = a->aa + aa->b = a->aa + bb->b,


上式进一步转化为:a->b = (3-delta[a]+delta[b])%3,


若一致则为真,否则为假。
*/


#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>

using namespace std;

#define MAXN 50010
int father[MAXN];
int rank[MAXN];
int ans=0;
int n,m;

void init(int x)
{
	int i;
	for(i=1;i<=n;i++)
	{
		father[i]=i;
		rank[i]=0;
	}
}
int find(int x)
{
	int t;
	if(father[x]==x)
		return x;
	t=find(father[x]);
	rank[x]=(rank[x]+rank[father[x]])%3;
	father[x]=t;
	return t;
}

void union_set(int x,int y,int d)
{
	if(x>n||y>n)
	{
		ans++;
		return ;
	}
	int a=find(x);
	int b=find(y);	
	if(a==b)
	{
		if((rank[x]-rank[y]+3)%3!=d)
		{
			ans++;
			return ;
		}
	}
	father[a]=b;
	rank[a]=(rank[y]+d+3-rank[x])%3;
	
}
int main()
{

	int x,y,d;
	int i;
	scanf("%d%d",&n,&m);
	init(n);
	while(m--)
	{
		scanf("%d%d%d",&d,&x,&y);
		union_set(x,y,d-1);
	}
	printf("%d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值