POJ1182-并查集

来源:互联网 发布:网络远程教育哪家好 编辑:程序博客网 时间:2024/05/18 18:43

这题有一个关键点: x的食物的食物以x为食,即生物间的关系是以3为循环的,就像运算 (0+1)%3=1,(1+1)%3=2,(2+1)%3=0,(0+1)%3=1... ...

不管d=1还是d=2,都表示x与y有关系,因此可以并到一个并查集里去,然而具体的同类与捕食关系可用0,1,2来代表;

这里以r[i]表示i与其并查集中父节点p[i]的关系: 0表示同类,1表示i吃p[i],2表是i被p[i]吃;

那么如果x和y在同一个并查集时,可通过查询x与根节点的关系,y与根节点的关系来判断x与y的关系。若在并查集的find操作中压缩路径的话,根节点也就成了父节点,好方便!

另外合并和查找时可以利用一些加法,对3取模的运算来更新r。

AC代码:

#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int NN=50005;int n;int p[NN]; //根节点int r[NN]; //与父节点的关系,0:同类,1:吃根节点,2:被根节点吃inline void get(int &x){    char c=getchar();    while (c<'0' || c>'9') c=getchar();    x=c-'0';    c=getchar();    while (c>='0' && c<='9') x=x*10+c-'0',c=getchar();}int find(int x){    if (p[x]!=x)    {        int t=p[x];        p[x]=find(p[x]);        r[x]=(r[x]+r[t])%3; //x与新父节点(根节点)的关系    }    return p[x];}int Union(int d,int x,int y){    int fx=find(x);    int fy=find(y);    p[fx]=fy;    r[fx]=(r[y]-r[x]+2+d)%3; //fx与fy的关系=y与fy的关系和x与fx的关系差+x与y的关系}int main(){    int d,x,y,k,cnt=0;    scanf("%d%d",&n,&k);    for (int i=1; i<=n; i++)    {        p[i]=i;        r[i]=0;    }    while (k--)    {        get(d); get(x); get(y);        if (x>n || y>n) cnt++;        else if (d==2 && x==y) cnt++;        else if (find(x)!=find(y)) Union(d,x,y);        else if ((r[y]+d+2)%3!=r[x]) cnt++;//这句话一定是在find(x)和find(y)之后的,因为find过后r[x]才是x与其根节点的关系    }    printf("%d\n",cnt);    return 0;}


原创粉丝点击