并查集:CDOJ1594-老司机的奇幻漂流 (食物链)

老司机的奇幻漂流 UESTC - 1594

Problem Description

老司机在救出了女票之后,就和她在全世界旅游,有一天,他们来到了一个神奇的小岛上。
这个小岛上有三种动物,他们互相克制,就像虚空追猎凤凰石头剪刀布一样,他们形成了一个食物环。
热爱小动物的老司机女票已经对这个岛上的N只动物进行了细致的研究,对他们所属的族群也了如指掌,并对他们的行为做了记录。
第一种记录方式是1 X Y,表示X和Y关系密切(是同类)。
第二种记录方式是2 X Y,表示X对Y有攻击性行为(X克制Y)。
不过很不凑巧,这些记录被毛手毛脚的JJ给打乱了,使得其中一些记录出现了错误。
为了安慰着急的女票,老司机急忙来帮忙查看是哪些记录出现了错误,当一条记录满足以下三种可能之一时,这就是一条错误的记录。
1)这条记录中的X或者Y比N大
2)攻击性记录中的X攻击了X
3)这条记录与前面的记录相悖
老司机说是来帮忙,但是还要忙着跑去和wyy踢fifa,所以就让你来完成这个任务,找出这些记录中哪些错了。
Input
第一行两个整数N和M,为记录的动物数量和记录条数
接下来M行,每行代表一条记录。

Output

一行n个数字,表示哪几条记录有误,用空格隔开
按编号升序输出

Sample Input

100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5

Sample Output

1 4 5
Hint

数据范围:

1<= N <= 50,000
1<= M <=100,000


  1. 这是一个食物链问题的并查集,算是并查集中比较高端的问题了,这里有一个很好的博客,想了解的可以去看看食物链并查集,其实在看了这个博客之后还不是很懂,但是模板大概是个什么样子还是知道了。这里面有一个很核心的公式:rootx->rooty = (relation[x]+d-1+3-relation[y])%3 = relation[rooty]

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
struct node
{
    int pre;
    int relation;
} p[maxn];

int find(int x)
{
    int temp;
    if(x == p[x].pre)
        return x;
    temp = p[x].pre;
    p[x].pre = find(temp);
    p[x].relation = (p[x].relation + p[temp].relation)%3;
    return p[x].pre;
}

int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        queue <int> qu;
        for(int i=1; i<=n; i++)
        {
            p[i].pre = i;
            p[i].relation = 0;
        }
        for(int i=1; i<=m; i++)
        {
            int a,b,c;
            cin>>c>>a>>b;
            if(a == b && c == 2)
            {
                qu.push(i);
                continue;
            }
            if(a > n || b > n)
            {
                qu.push(i);
                continue;
            }
            int fa = find(a);
            int fb = find(b);
            if(fa != fb)
            {
                p[fb].pre = fa;
                p[fb].relation = (3 + (c - 1) + p[a].relation - p[b].relation)%3;//很重要的合并公式
                //rootx->rooty = (relation[x]+d-1+3-relation[y])%3 = relation[rooty](公式)
            }
            else
            {
                if(c == 1 && p[a].relation != p[b].relation)//同类但是和父类的关系不同是不可能的
                    qu.push(i);
                if(c == 2 && ((3 - p[a].relation + p[b].relation)%3 != c -1))//检验是否是符合捕食关系
                    qu.push(i);
            }
        }
        if(qu.empty())
            continue;
        printf("%d",qu.front());
        qu.pop();
        while(!qu.empty())
        {
            printf(" %d",qu.front());
            qu.pop();
        }
    }
    return 0;
}


posted @ 2017-07-30 14:41  GoldenFingers  阅读(153)  评论(0编辑  收藏  举报