• 并查集入门题


     POJ 1611

    题意:给你各个集合包含的元素,求0所在的集合总共有多少个不相同的元素。
    题解:维护一个size即可,注意size是在什么时候进行相加的。

    //#include <bits/stdc++.h>
    #include <cstdio>
    using namespace std;
    
    int fa[30005], size[30005];
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    
    int main()
    {
        int n, m;
        while(~scanf("%d%d", &n, &m))
        {
            if(n==0 && m==0) break;
            for(int i=0; i<n; i++)
                fa[i]=i, size[i]=1;
            for(int i=0; i<m; i++)
            {
                int cnt, x, y; 
                scanf("%d", &cnt);
                if(cnt) scanf("%d", &x);
                for(int i=1; i<cnt; i++)
                {
                    scanf("%d", &y);
                    int px=find(x), py=find(y);
                    if(px!=py){
                        size[px]+=size[py];
                        fa[py]=px;    
                    }    
                }
            }
            int p=find(0);
            printf("%d
    ", size[p]);
        }
        return 0;
    } 
    View Code

    POJ 1988 cube stacking

    题意: 有N(N<=30,000)堆方块,开始每堆都是一个方块,方块编号1 – N. 有两种操作:
    • M x y : 表示把方块x所在的堆,拿起来叠放到y所在的堆上。
    • C x : 问方块x下面有多少个方块。
    • 操作最多有 P (P<=100,000)次。对每次C操作,输出结果

    题解:形成一种树形结构,直接用带权并查集维护,size,under 即可。注意路径压缩的过程中别写错了。

    //#include <bits/stdc++.h>
    #include <cstdio>
    using namespace std;
    
    const int maxn=30005;
    int fa[maxn], under[maxn], size[maxn];
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        int t=find(fa[x]);
        under[x]+=under[fa[x]]; // 注意是加上under[fa[x]]而不是under[t] 
        return fa[x]=t;
    }
    
    void merge(int x, int y)
    {
        int px=find(x), py=find(y);
        if(px!=py){ 
            under[py]=size[px];   //注意在合并之前,把所有要维护的都维护掉 
            size[px]+=size[py];
            fa[py]=px; 
        }
    }
    
    void init(int n)
    {
        for(int i=1; i<=maxn; i++)
        {
            size[i]=1;
            under[i]=0;
            fa[i]=i;
        }
    }
    
    int main()
    {
        int n; 
        scanf("%d", &n);
        init(n);
        for(int i=0; i<n; i++)
        {
            char cmd[10];
            int x, y;
            scanf("%s", cmd);
            if(cmd[0]=='M'){
                scanf("%d%d", &x, &y);
                merge(y, x);
            }
            else{
                scanf("%d", &x);
                find(x);          //注意要先路径压缩后在直接输出 
                printf("%d
    ", under[x]);
            }
        }
        return 0;
    }
    View Code

    BZOJ 1202  [HNOI2005] 狡猾的商人

    题意:给你多个区间u到v的和为w,问是否会有冲突,每个位置的值可以是负数。
    题解:判断时候只有知道了x-y,x-z,才能判断y-z是否冲突。故使用并查集维护区间和,根节点为起点,在同一个并查集内必然可以判断是否冲突。

    #include <bits/stdc++.h>
    
    int val[105], fa[105], ok;
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        int t=find(fa[x]);
        val[x]+=val[fa[x]];
        return fa[x]=t;
    }
    
    void merge(int u, int v, int w)
    {
        int pu=find(u), pv=find(v);
        if(pu!=pv){
            val[pv]=-val[v]-w+val[u];
            fa[pv]=pu;
        }
        else{
            if(val[v]-val[u]!=-w) ok=0;
        }
    }
    
    int main()
    {
        int T;
        for(scanf("%d", &T); T--; )
        {
            int n, m;
            scanf("%d%d", &n, &m);
            for(int i=0; i<=n; i++)
                val[i]=0, fa[i]=i;
            ok=1;
            for(int i=0; i<m; i++)
            {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                merge(u-1, v, w);           //起点往左边移动一位方便计算
            }
            printf("%s
    ", ok? "true":"false");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【转】每天一个linux命令(52):ifconfig命令
    【转】每天一个linux命令(51):lsof命令
    linux挂载SD卡
    【转】每天一个linux命令(50):crontab命令
    【转】每天一个linux命令(49):at命令
    【转】每天一个linux命令(48):watch命令
    【转】每天一个linux命令(47):iostat命令
    【转】每天一个linux命令(46):vmstat命令
    【转】每天一个linux命令(45):free 命令
    【转】每天一个linux命令(44):top命令
  • 原文地址:https://www.cnblogs.com/Yokel062/p/11474954.html
Copyright © 2020-2023  润新知