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

算法笔记

带权并查集大神详解: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]的值。这点也是我最近才考虑清楚的,以前太菜了,没想清楚就以为自己懂了。

转载于:https://www.cnblogs.com/widsom/p/7121629.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值