poj 1182 食物链 并查集
解题方法
需要画图 首先把祖先到祖先的距离设置为0 祖先要吃的动物赋值为2 吃祖先的动物为1 为什么这样设置呢!首先所有的动物到祖先距离都为0;
当有动物吃祖先的时候,他到祖先的距离变化为1 当有动物吃这个到祖先距离为1的动物时,这个动物到祖先的距离变成2,如果有动物吃这个到祖先的距离为2的动物时,这个动物到祖先的距离为3;因为这有三种动物,所以第三种动物就是祖先(用%3 的方法就可以更新出这个动物正确的等级)到这里都只能够是判断共祖先的动物是否存在吃与被吃的关系;如果两个不相干的集合要放到一个集合;怎么办呢! 不妨画个图,
![](http://images0.cnblogs.com/blog/450714/201303/02213301-7e7e90fbbc584282a4ec2c3ae4cd0894.png)
这两个图如何合并成一个图呢! 加入存在 这个集合的蛇 吃 这个集合的鸟 看看这个方程 dis[鸟] + 1 + dis[虫祖] == dis[蛇] 这样 第1个集合通过改变祖先的值使得这个祖先的鸟能获取正确的值;因为第一个集合的三个元素的值都增加了1 所以就相当于顺时钟转了一圈,这样答案就对;
#include<iostream> #include<stdio.h> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int f[50004],dis[50004]; int find( int x ) { if( f[x] == x ) return x; int t = find( f[x] ); dis[x] = ( dis[x] + dis[f[x]] )%3; f[x] = t; return t; } int main( ) { int i,u,v,d,ans,N,K; scanf("%d%d",&N,&K); for( i = 0; i <= N; i++ ) f[i] = i,dis[i] = 0; ans = 0; for( i = 1; i <= K; i++ ) { scanf("%d%d%d",&d,&u,&v);d--; if( u > N || v > N ) {ans++;continue;} int a = find( u ); int b = find( v ); if( a == b ) { if( !d && dis[u] != dis[v] )ans++; if( d && ( dis[u] - dis[v] == 0 || dis[u] - dis[v] == -1 || dis[u] - dis[v] == 2 ) ) ans++; } else { f[b] = a; dis[b] = ( dis[u] - dis[v] - d + 6 )%3 ; } } printf("%d\n",ans); }