算法筆記--帶權並查集及其模板題。


算法筆記

帶權並查集大神詳解: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\n");
        else printf("%d\n",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]的值。這點也是我最近才考慮清楚的,以前太菜了,沒想清楚就以為自己懂了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM