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

本文介绍了带权并查集的实现原理,并通过三道典型例题Poj1182食物链、Hiho1515分数调查及Codeforces 766D-Mahmoud and a Dictionary详解其应用技巧。每道题都附有完整代码示例,有助于读者快速掌握带权并查集的使用。

算法笔记

带权并查集大神详解: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

乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值