• 种类并查集学习


    种类并查集

    学习网站:https://zhuanlan.zhihu.com/p/97813717

    种类并查集(包括普通并查集)维护的是一种循环对称的关系。

    img

    A Bug's Life

    题目大意:研究表明虫子都是异性相吸,给你 (n) 对虫子,(a)(b) 表示这两只虫子相互吸引。问是否可以找到两只虫子是同行相吸,如果可以,请输出“Suspicious bugs found!”,否则请输出“No suspicious bugs found!”

    题解:

    这个题目很简单,可以把所有相同性别的人放到一个圈里,然后判断 (a)(b) 是不是在一个圈里即可。

    我们开一个两倍大小的并查集。例如,假如我们要维护4个元素的并查集,我们改为开8个单位的空间:

    img

    (i+n) 表示与 (i) 的性别不同。

    那么如果 1 和 2 的性别不同,那么 (merge(1,n+2)) (merge(n+1,2))

    这样如果可以通过式子得到同行相吸则一定是在一个圈里。

    #include <cstdio>
    #include <cstdlib>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define debug(x) printf("debug:%s=%d
    ",#x,x);
    //#define debug(x) cout << #x << ": " << x << endl
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e6+10;
    int f[maxn],a[maxn],b[maxn];
    void init(int n){
        for(int i=0;i<=2*n;i++) f[i]=i;
    }
    
    int findx(int x){
        return f[x]==x?x:f[x]=findx(f[x]);
    }
    
    void merge(int x,int y){
        x=findx(x);
        y=findx(y);
        if(x==y) return ;
        f[x]=y;
    }
    
    bool same(int x,int y){
        return findx(x)==findx(y);
    }
    
    int main(){
        int t;
        scanf("%d",&t);
        for(int cas=1;cas<=t;cas++){
            int n,m,ans=0;
            scanf("%d%d",&n,&m);
            init(2*n);
            for(int i=1;i<=m;i++){
                scanf("%d%d",&a[i],&b[i]);
                if(same(a[i],b[i])) ans = 1;
                merge(a[i],b[i]+n);
                merge(b[i],a[i]+n);
            }
            printf("Scenario #%d:
    ",cas);
            if(ans) printf("Suspicious bugs found!
    ");
            else printf("No suspicious bugs found!
    ");
            printf("
    ");
        }
    }
    

    P2024 [NOI2001]食物链

    我们会发现,A、B、C三个种群天然地符合用种类并查集维护的要求。

    img

    于是我们可以用一个三倍大小的并查集进行维护,用 (i+n) 表示 (i) 的捕食对象,而 (i+2n) 表示 (i) 的天敌。

    • 对于 (a)(b) 如果是同类关系,则 (a+n)(b+n) 也是同类, (a+2*n)(b+2*n) 也是同类

    • 如果 (a)(b) 如果是捕食关系,则 (a)(b+n) 也是捕食关系,(a+n)(b+2*n) 也是捕食关系

    所以只要判断有没有矛盾即可。

    #include <cstdio>
    #include <cstdlib>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define debug(x) printf("debug:%s=%d
    ",#x,x);
    //#define debug(x) cout << #x << ": " << x << endl
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 5e5+10;
    int f[maxn];
    void init(int n){
        for(int i=0;i<=n;i++) f[i]=i;
    }
    
    int findx(int x){
        return f[x]==x?x:f[x]=findx(f[x]);
    }
    
    void merge(int x,int y){
        x=findx(x);
        y=findx(y);
        if(x==y) return ;
        f[x]=y;
    }
    
    bool same(int x,int y){
        return findx(x)==findx(y);
    }
    
    int main(){
        int n,k,ans=0;
        scanf("%d%d",&n,&k);
        init(3*n);
        for(int i=1;i<=k;i++){
            int opt,x,y;
            scanf("%d%d%d",&opt,&x,&y);
            if(x<=0||y<=0||x>n||y>n||(opt==2&&x==y)) {
                ans++;
                continue;
            }
    
            if(opt==1){
                if(same(x,y+n)||same(x,y+2*n)) ans++;
                else merge(x,y),merge(x+n,y+n),merge(x+2*n,y+2*n);
            }
            else{
                if(same(x,y)||same(x,y+n)) ans++;
                else merge(x,y+2*n),merge(x+n,y),merge(x+2*n,y+n);
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    P1525 关押罪犯

    这里也有满足种类并查集的关系

    img

    我们开一个两倍大小的并查集。例如,假如我们要维护4个元素的并查集,我们改为开8个单位的空间:

    img

    对于罪犯i,i+n为他的敌人
    所以如果 1 和 2 是敌人,那么merge(1,n+2),merge(n+1,2)
    表示1要连向2的敌人,1和2的敌人是好朋友
        2要连向1的敌人,2和1的敌人是好朋友
    只要最后不连成一个圈则表示可以进行合理分配使得没有冲突事件的影响力
    如果连成一个圈,则表示前面分配完不在一个监狱之后当前的a,b一定会处于同一个监狱
    因为要冲突事件影响力越小越好,所以贪心的考虑先排影响力大的罪犯
    
    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define debug(x) printf("debug:%s=%d
    ",#x,x);
    //#define debug(x) cout << #x << ": " << x << endl
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 5e5+10;
    int f[maxn];
    struct node{
       int a,b,c;
       node(int a=0,int b=0,int c=0):a(a),b(b),c(c){}
    }e[maxn];
    bool cmp(node a,node b){
       return a.c>b.c;
    }
    void init(){
       for(int i=0;i<=maxn;i++) f[i]=i;
    }
    
    int findx(int x){
       return f[x]==x?x:f[x]=findx(f[x]);
    }
    
    void merge(int x,int y){
       x=findx(x);
       y=findx(y);
       if(x==y) return ;
       f[x]=y;
    }
    
    bool same(int x,int y){
       return findx(x)==findx(y);
    }
    
    int main(){
       int n,m,ans=0;
       scanf("%d%d",&n,&m);
       init();
       for(int i=1;i<=m;i++){
           int a,b,c;
           scanf("%d%d%d",&a,&b,&c);
           e[i]=node(a,b,c);
       }
       sort(e+1,e+1+m,cmp);
       for(int i=1;i<=m;i++){
           if(same(e[i].a,e[i].b)) {
               ans = e[i].c;
               break;
           }
           merge(e[i].a,e[i].b+n);
           merge(e[i].b,e[i].a+n);
       }
       printf("%d
    ",ans);
       return 0;
    }
    
  • 相关阅读:
    IP查询网和traceroute找到的网络出口不一致的原因
    [转载] 深入理解VMware虚拟机网络通信原理
    https工作流程
    HTTP1.1协议-RFC2616-中文版
    条件变量调用Signal的时候是否需要持有mutex
    HTTP Get一定是幂等的吗,统计访问量的时候呢?
    unix网络编程
    MySQL-SQL基础-DCL
    MySQL-SQL基础-查询1
    MySQL-SQL基础-子查询
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13276559.html
Copyright © 2020-2023  润新知