UESTC 1594 老司机的奇幻漂流 并查集+食物链

老司机的奇幻漂流

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)


Submit  Status
老司机在救出了女票之后,就和她在全世界旅游,有一天,他们来到了一个神奇的小岛上。
这个小岛上有三种动物,他们互相克制,就像虚空追猎凤凰石头剪刀布一样,他们形成了一个食物环。
热爱小动物的老司机女票已经对这个岛上的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 and output

Sample Input Sample Output
100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

1 4 5


Hint

数据范围:
1<= N <= 50,000
1<= M <=100,000


Source

2017 UESTC Training for Data Structures

UESTC 1594 老司机的奇幻漂流


My Solution

题意:三个东西构成一个食物链关系,A->B, B->C, C->A,给出m条关系,问是否有矛盾。


并查集 食物链
每个点有三个成员A、B、C,
当X和Y是同类时, _merge(X, Y), _merge(X+n, Y+n), _merge(X+2*n, Y+2*n);
当X攻击Y时, _merge(X+n, Y), _merge(X+2*n, Y+n), _merge(X, Y+2*n);


每次判断是否 if(x > n || x < 1 || y > n || y < 1){
            ans.push_back(i);
            continue;
        }
然后插入前判断
如果是同类 if(_find(x+n) == _find(y) || _find(x) == _find(y+n)){
                ans.push_back(i);
                continue;
            }
如果X攻击Y if(_find(x) == _find(y) || _find(x) == _find(y+n)){
                ans.push_back(i);
                continue;
            }
复杂度 O(n)


#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int MAXN = 5e4 + 8;

int father[3*MAXN], _rank[3*MAXN];
inline void DisjointSet(int n)
{
    for(int i = 0; i <= 3*n; i++){
        father[i] = i;
    }
}

inline int _find(int v)
{
    return father[v] = father[v] == v ? v : _find(father[v]);
}

inline void _merge(int x, int y)
{
    int a = _find(x), b = _find(y);                //
    if(_rank[a] < _rank[b]){
        father[a] = b;
    }
    else{
        father[b] = a;
        if(_rank[a] == _rank[b]){
            _rank[a]++;
        }
    }
}

vector ans;

int main()
{
    #ifdef LOCAL
    freopen("l.txt", "r", stdin);
    //freopen("l.out", "w", stdout);
    int T = 4;
    while(T--){
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    int n, m, t, x, y, i;
    scanf("%d%d", &n, &m);
    DisjointSet(n);
    for(i = 1; i <= m; i++){
        scanf("%d%d%d", &t, &x, &y);
        if(x > n || x < 1 || y > n || y < 1){
            ans.push_back(i);
            continue;
        }
        if(t == 1){
            if(_find(x+n) == _find(y) || _find(x) == _find(y+n)){
                ans.push_back(i);
                continue;
            }
            _merge(x, y);
            _merge(x + n, y + n);
            _merge(x + 2*n, y + 2*n);

        }
        else{
            if(_find(x) == _find(y) || _find(x) == _find(y+n)){
                ans.push_back(i);
                continue;
            }
            _merge(x + n, y);
            _merge(x + 2*n, y + n);
            _merge(x, y + 2*n);

        }

    }

    if(ans.empty()) printf("0");
    else{
        sort(ans.begin(), ans.end());
        int sz = ans.size();
        for(int i = 0; i < sz; i++){
            if(i == 0) printf("%d", ans[i]);
            else printf(" %d", ans[i]);
        }
       // putchar('\n');
    }


    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}



  Thank you!

                                                                                                                                             ------from ProLights

你可能感兴趣的:(☺藏题阁☺,数据结构:并查集,数据结构:技巧,UESTC,OJ,算法的艺术)