• 算法笔记--带权并查集及其模板题。


    算法笔记

    带权并查集大神详解:https://agatelee.cn/2017/05/%E5%B8%A6%E6%9D%83%E5%B9%B6%E6%9F%A5%E9%9B%86/

    贴几道题的代码:

    Poj1182食物链

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1e5+5;
    int fa[N],rnk[N];
    void Init(int n)
    {
        for(int i=0;i<=n;i++)
        {
            fa[i]=i;
            rnk[i]=0;
        }
    }
    int Find(int x)
    {
        if(x==fa[x])return x;
        int temp=fa[x];
        fa[x]=Find(fa[x]);
        rnk[x]=(rnk[x]+rnk[temp])%3;
        return fa[x];
    }
    void Merge(int r,int x,int y)
    {
        int rx=Find(x);
        int ry=Find(y);
        if(rx==ry)return  ;
        fa[rx]=ry;
        rnk[rx]=(r+rnk[y]-rnk[x]+3)%3;
    }
    int main()
    {
        int n,k;
        cin>>n>>k;
        Init(n);
        int ans=0;
        while(k--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            a--;
            if(b>n||c>n)
            {
                ans++;
                continue;
            }
            if(a==1&&b==c)
            {
                ans++;
                continue;
            }
            int rb=Find(b);
            int rc=Find(c);
            if(rb!=rc)Merge(a,b,c);
            else
            {
                if((rnk[b]-rnk[c]+3)%3!=a)ans++;
            }
        }
        cout<<ans<<endl;
        return 0;
    }

    这道题目不知道为啥用ios::sync_with_stdio(false)和cin是TLE,用ios:cync_with_stdi(false)和scanf()是WA。

    详见知乎:用ios::sync_with_stdio(false)有什么坏处

    Hiho 1515分数调查

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1e5+5;
    int fa[N],rnk[N];
    void Init(int n)
    {
        for(int i=0;i<=n;i++)
        {
            fa[i]=i;
            rnk[i]=0;
        }
    }
    int Find(int x)
    {
        if(x==fa[x])return x;
        int temp=fa[x];
        fa[x]=Find(fa[x]);
        rnk[x]=rnk[x]+rnk[temp];
        return fa[x];
    }
    void Merge(int s,int x,int y)
    {
        int rx=Find(x);
        int ry=Find(y);
        if(rx==ry)return  ;
        fa[rx]=ry;
        rnk[rx]=s+rnk[y]-rnk[x];
    }
    int main()
    {
        int n,m,q;
        cin>>n>>m>>q;
        Init(n);
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            Merge(c,a,b);
        }
        while(q--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            int ra=Find(a);
            int rb=Find(b);
            if(ra!=rb)printf("-1
    ");
            else printf("%d
    ",rnk[a]-rnk[b]);
        }
        return 0;
    }

    Codeforces 766D - Mahmoud and a Dictionary

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int fa[N],rnk[N];
    map<string,int>ma;
    void Init(int n)
    {
        for(int i=0;i<=n;i++)
        {
            fa[i]=i;
            rnk[i]=0;
        }
    }
    int Find(int x)
    {
        if(x==fa[x])return x;
        int temp=fa[x];
        fa[x]=Find(fa[x]);
        rnk[x]=(rnk[x]+rnk[temp])%2;
        return fa[x];
    }
    void Merge(int r,int x,int y)
    {
        int rx=Find(x);
        int ry=Find(y);
        if(rx==ry)return;
        fa[rx]=ry;
        rnk[rx]=(r+rnk[y]-rnk[x]+2)%2;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,m,q;
        cin>>n>>m>>q;
        Init(n);
        int a;
        string s1,s2;
        for(int i=0;i<n;i++)
        {
            cin>>s1;
            ma[s1]=i;
        }
        while(m--)
        {
            cin>>a>>s1>>s2;
            a--;
            int rs1=Find(ma[s1]);
            int rs2=Find(ma[s2]);
            if(rs1!=rs2)
            {
                Merge(a,ma[s1],ma[s2]);
                cout<<"YES"<<endl;
            }
            else
            {
                if((rnk[ma[s1]]-rnk[ma[s2]]+2)%2!=a)
                    cout<<"NO"<<endl;
                else cout<<"YES"<<endl;
            }
        }
        while(q--)
        {
            cin>>s1>>s2;
            int rs1=Find(ma[s1]);
            int rs2=Find(ma[s2]);
            if(rs1!=rs2)cout<<3<<endl;
            else cout<<((rnk[ma[s1]]-rnk[ma[s2]]+2)%2+1)<<endl;
        }
        return 0;
    }

    ps:

    可以用向量的方法考虑rnk之间的变化;

    rnk[i] 表示的是i与i直接父亲节点的关系,在没有路径压缩之前不是i与根节点的关系,在路径压缩之后直接父亲就是根节点,此时才是与根节点的关系。所以只需要在直接父亲改变的情况下才需要改变rnk[i]的值。这点也是我最近才考虑清楚的,以前太菜了,没想清楚就以为自己懂了。

  • 相关阅读:
    【BZOJ4448】【SCOI2015】情报传递
    【BZOJ2006】【NOI2010】超级钢琴
    NOIp2018模拟赛四十五~??
    【BZOJ4940】【YNOI2016】这是我自己的发明
    数据迁移—datax
    DG模拟GAP手动处理
    DG问题:ORA-16416: No viable Physical Standby switchover targets available
    管理和维护DG
    DG问题
    DG概念与机制
  • 原文地址:https://www.cnblogs.com/widsom/p/7121629.html
Copyright © 2020-2023  润新知