• 种类并查集


    种类并查集

    普通的并查集维护的关系是: 朋友的朋友是朋友,即如果 A ~ B 是一对朋友, B ~ C 是一对朋友, 那么 A~C 是一对朋友。但如果我们需要维护这样一个关系“朋友的朋友是朋友,朋友的敌人是敌人,敌人的敌人是朋友”,普通的并查集就无能为力了。因此,需要引入种类并查集。

    例题

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

    Input

    第一行是两个整数N和K,以一个空格分隔。
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
    若D=1,则表示X和Y是同类。
    若D=2,则表示X吃Y。

    Output

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

    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

    3

    我们定义: 如果 a吃a+n,a+n吃a+2n,a+2n吃a

    截屏2020-07-16 上午11.09.21

    对于给定的两个动物 A和B:

    • A是B的同类

      A和B是同类

      A+n和B+n是同类

      A+2n和B+2n是同类

    • A吃B

      A吃B (Rightarrow) A+n和B是同类

      A+n吃B+n (Rightarrow) A+2n和B+n是同类

      A+2n吃B+2n (Rightarrow) A和B+2n是同类

    • A被B吃

      A被B吃 (Rightarrow) A和B+n是同类

      A+n被B+n吃 (Rightarrow) A+n和B+2n是同类

      A+2n被B+2n吃 (Rightarrow) A+2n和B是同类

    这题第一次交TLE,好像不能用cin吧,我这里用快读了。按秩合并不需要用,只写路径压缩一样能过。

    #include <cstdio>
    #define Maxsize 50000+1
    using namespace std;
    int n,k;
    inline int read(){
        int x = 0;
        char c = getchar();
        while (c<'0'||c>'9') {
            c = getchar();
        }
        while (c>='0'&&c<='9') {
            x = (x<<1) + (x<<3) + (c^48);
            c = getchar();
        }
        return x;
    }
    int Book[3*Maxsize];
    int Rank[3*Maxsize];
    // i 吃 i + n, i + n 吃  i + 2n , i + 2n 吃 i
    inline int  Find(int a){
        if(Book[a] == a)return a;
        else return Book[a] = Find(Book[a]);
    }
    inline void Union(int a,int b){
        int af = Find(a);
        int bf = Find(b);
        if(Rank[af] > Rank[bf]){
            Book[bf] = af;
        }else if(Rank[af] < Rank[bf]){
            Book[af] = bf;
        }else{
            Book[bf] = af;
            Rank[af]++;
        }
    }
    inline void be_same(int a,int b){
        Union(a,b);
        Union(a+n,b+n);
        Union(a+2*n,b+2*n);
    }
    inline void a_eat_b(int a,int b){
        Union(a+n,b);
        Union(a+2*n,b+n);
        Union(a,b+2*n);
    }
    
    inline bool is_same(int a,int b){
        return Find(a) == Find(b);
    }
    void init(int n){
        for(int i = 1; i <= n; i++)
            Book[i] = i;
    }
    int main(){
        n = read(); k = read();
        init(3*n);
        int ans = 0;
        int a,b,type;
        
        while(k--){
            type = read(); a = read(); b = read();
            if(a > n || b > n){
                ans++;
                continue;
            }
            if(type == 1){ // a 和 b 是同类
                if(is_same(a,b+n) || is_same(a,b+2*n))
                    ans++;
                else
                    be_same(a,b);
            }else{ // a 吃 b
                if(a == b)
                    ans++;
                else if(is_same(a,b) || is_same(a,b+n))
                    ans++;
                else
                    a_eat_b(a,b);
            }
        }
        printf("%d",ans);
        return 0;
    }
    
    

    参考: https://zhuanlan.zhihu.com/p/42496208

    ---- suffer now and live the rest of your life as a champion ----
  • 相关阅读:
    myeclipse的debug模式启动不了,但run模式可以启动
    修改tomcat的端口号
    mybatis报错:Caused by: java.lang.IllegalArgumentException: Caches collection already contains value for com.crm.dao.PaperUserMapper
    mysql报错:java.sql.SQLException: Incorrect string value: 'xE4xB8x80xE6xACxA1...' for column 'excelName' at row 1
    修改tomcat命令黑窗口的名字
    myeclipse无法部署项目的解决
    我说精通字符串,面试官竟然问我 Java 中的 String 有没有长度限制?
    14个Java并发容器,你用过几个?
    6 种微服务 RPC 框架,你知道几个?
    Java中Set与Set<?>到底区别在哪?
  • 原文地址:https://www.cnblogs.com/popodynasty/p/13321839.html
Copyright © 2020-2023  润新知