poj1182

题意:ABC三个物种构成循环捕食的食物网。给出一些捕食与同类 关系,询问一些关系是否正确。

分析:并查集,但要随时记录并更新每个元素与其父亲之间的关系。用rank数组记录与父亲的关系。若为rank[x]==1则x吃其父亲,0表示同类,-1表示被吃。我们认为并查集中每个集合中的所有的动物都站在一条数轴上,每个点可以站多个动物,他们占据了一些连续的点。若b在a的右邻位则b吃a,若a,b相距是3的整数倍,则ab同类。这样以来rank数组的意义就变成了该动物与其父亲的在数轴上的差距(有正负)。当我们确定了a,b到祖先的距离时,只需要用rank[a]-rank[b]就可以获得a到b的距离。

View Code
#include < iostream >
#include
< cstdio >
#include
< cstdlib >
#include
< cstring >
using namespace std;

#define maxn 50005

int n, m;
int father[maxn], rank[maxn];

int getanc( int a)
{
if (father[a] == a)
return a;
int ret = getanc(father[a]);
rank[a]
= (rank[father[a]] + rank[a]) % 3 ;
father[a]
= ret;
return ret;
}

void merge( int a, int b)
{
father[getanc(a)]
= getanc(b);
}

bool ok( int order, int a, int b)
{
if (a > n || b > n || (order == 2 && a == b))
return false ;
int fa = getanc(a);
int fb = getanc(b);
if (fa != fb)
{
merge(fa, fb);
rank[fa]
= (rank[b] - rank[a] + order - 1 + 3 ) % 3 ;
return true ;
}
return (rank[a] - rank[b] + 3 ) % 3 == order - 1 ;
}

int main()
{
// freopen("t.txt", "r", stdin);
scanf( " %d%d " , & n, & m);
for ( int i = 0 ; i < n; i ++ )
father[i]
= i;
memset(rank,
0 , sizeof (rank));
int ans = 0 ;
for ( int i = 0 ; i < m; i ++ )
{
int order, a, b;
scanf(
" %d%d%d " , & order, & a, & b);
if ( ! ok(order, a, b))
ans
++ ;
}
printf(
" %d\n " , ans);
return 0 ;
}

你可能感兴趣的:(poj)