POJ 1182 食物链【并查集】

题意:

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

分析: 每当出现一个新的关系,判断已有的关系是否和其冲突,如果不冲突,那么加入之后立即更新祖先和孩子的关系。

          加入一个记录每个元素和祖先关系的数组 r[].

          r[i] = 0  : 表示 i 和祖先是同一个物种。

          r[i] = 1  :   表示 i 的祖先 吃 i 这个物种。

          r[i] = 2  :   表示 i 吃自己的祖先。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
#define INF 0x1f1f1f1f
int f[500005];
int r[500005];
int n,m;
int find(int x)
{
    int s;
    if(f[x]==-1)
        return x;
    else s=find(f[x]);
    r[x]=(r[x]+r[f[x]])%3;
    f[x]=s;
    return s;
}
void join(int x,int y,int w)
{
    int fx=find(x);
    int fy=find(y);
    f[fy]=fx;
    r[fy]=(r[x]-r[y]+w+3)%3;
}
int main()
{
    scanf("%d%d",&n,&m);
    int res=0,a,b,w;
    clr(r);
    memset(f,0xff,sizeof(f));
    while(m--)
    {
        scanf("%d%d%d",&w,&a,&b);
        if(a>n||b>n)
        {
            res++;
            continue;
        }
        else
        {
            int fx=find(a);
            int fy=find(b);
            if(fx==fy)
            {
                if(w==1&&r[a]!=r[b])  {  res++;  continue;  }
                if(w==2&&((r[a]+1)%3!=r[b]||a==b)){ res++; continue;  }
            }
            else 
                join(a,b,w-1);
        }
    }
    printf("%d\n",res);
    return 0;
}

 

posted @ 2012-07-30 14:15  'wind  阅读(184)  评论(0编辑  收藏  举报