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>
usingnamespace 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))
returnfalse;
int fa = getanc(a);
int fb = getanc(b);
if (fa != fb)
{
merge(fa, fb);
rank[fa]
= (rank[b] - rank[a] + order -1+3) %3;
returntrue;
}
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);
return0;
}
原文地址:https://www.cnblogs.com/rainydays/p/2090313.html