AcWing:240. 食物链(扩展域并查集)

动物王国中有三类动物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和K句话,输出假话的总数。

输入格式

第一行是两个整数N和K,以一个空格分隔。

以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。

若D=1,则表示X和Y是同类。

若D=2,则表示X吃Y。

输出格式

只有一个整数,表示假话的数目。

数据范围

1N500001≤N≤50000,
0K1000000≤K≤100000

输入样例:

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

输出样例:

3

题解:

扩展域并查集:我们把每个动物拆成3个节点,分别是同类域xself,捕食域xeat,天敌域xenemy。

#include <iostream>
#include <cstdio>

using namespace std;

const int maxn = 3e5+7;

int f[maxn];

int get(int x) {
    if(x == f[x]) {
        return f[x];
    }
    int root = get(f[x]);
    return f[x] = root;
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= 3 * n; i++) {
        f[i] = i;
    }
    int ans = 0;
    while(m--) {
        int op, x, y;
        scanf("%d %d %d", &op, &x, &y);
        int x_self = x, x_eat = x + n, x_enemy = x + n + n;
        int y_self = y, y_eat = y + n, y_enemy = y + n + n;
        if(x > n || y > n) {    //动物编号不存在
            ans++;
        } else if(op == 1) {    //x和y是同类关系
            if(get(x_eat) == get(y_self) || get(x_self) == get(y_eat)) {    //如果x捕食的物种和y的同类在同一集合,或者x的同类和y捕食的物种在同一集合,那么不成立,此话是假
                ans++;
            } else {    //合并同类物种
                f[get(x_self)] = get(y_self);
                f[get(x_eat)] = get(y_eat);
                f[get(x_enemy)] = get(y_enemy);
            }
        } else {    //x和y是捕食关系,x吃y
            if(get(x_self) == get(y_self) || get(x_self) == get(y_eat)) {    //如果x的同类和y的同类在同一集合,或者x的同类和y捕食的物种在同一集合,那么不成立,此话是假
                ans++;
            } else {    //合并同类物种
                f[get(x_eat)] = get(y_self);
                f[get(x_self)] = get(y_enemy);
                f[get(x_enemy)] = get(y_eat);
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/buhuiflydepig/p/11396963.html