带权并查集浅谈

笔者最近刷到了一道带权并查集的题目,当做入门博客写一篇学习笔记吧。

题目链接

题目中要求求距离+换爹,很显然,暴力的dfs在20000的数据下绝对会被卡的。

自然想到,什么数据结构可以快速维护父子关系?

显然有并查集。

那么,我们要做的就是修改并查集,使它能够维护距离了。

那么,我们在每一次更新父亲(路径压缩)的时候更新距离。

先来看最基本的find函数:

inline int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}

我们要在这时候维护距离dis的改变。

于是,我们先记录下路径压缩前的父亲。

然后压缩。

返回的时候,当前的结点要累加之前的距离即可。

代码:

inline int find(int x){
    if(x==f[x])return x;
    int t=f[x];//记录之前父亲 
    f[x]=find(f[x]);//并查集find 
    dis[x]+=dis[t];//累加距离 
    return f[x];
}

对于多组训我,切记清空数组。并查集的初始化不要忘记。

将dis数组初始化为0,f数组照常赋值成自己。

对于第一个操作,直接认爹,然后更新距离。

所以,对于第二个E操作,在询问的时候要find一下,以便于更新之前没有更新的距离。之后直接输出即可。

注意,dis[x]维护的是x到根的距离。

并查集是树形结构。

总代码:

#include<cstdio>//加权并查集 
#include<iostream>
#include<cstring>
using namespace std;
int dis[50000],f[50000];
int n,x,y,t;
char s[50];
/*st
struct node{
    int next,to;
}; 
head[5000];
inline void add(int x,int y){
    e[++tot].to=y;
    e[tot].next=head[x];
    head[x]=tot;
}*/
inline int abs(int x){return x<0?-x:x;}
inline void read(int &x){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')w=-1;
        ch=getchar();
    }while(ch>='0'&&ch<='9'){
        s=(s<<1)+(s<<3)+(ch^48);
        ch=getchar();
    }x=s*w;
}
inline int find(int x){
    if(x==f[x])return x;
    int t=f[x];//记录之前父亲 
    f[x]=find(f[x]);//并查集find 
    dis[x]+=dis[t];//累加距离 
    return f[x];
}
inline void init(){
    memset(dis,0,sizeof(dis));
    for(int i=1;i<=n;++i)f[i]=i;
}
int main(){
    read(t);
    while(t--){
        read(n);
        init();
        while(1){
            cin>>s;
            if(s[0]=='O')break;
            if(s[0]=='I'){
                read(x);
                read(y);
                f[x]=y;
                dis[x]+=abs(x-y)%1000;
            }else{
                read(x);
                find(x);
                printf("%d\n",dis[x]);
            }
        }
    }
    return 0;
}

留一道例题,笔者之后补题解。

题目链接(种类并查集)

题解

例题2

转载于:https://www.cnblogs.com/h-lka/p/11158449.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
带权并查集(Weighted Union-Find)是在普通并查集的基础上进行了扩展,它在每个节点上存储了额外的权重信息。带权并查集主要用于解决一些需要考虑权重或者秩的问题,例如求解最小生成树、最大连通子图等。 在普通并查集中,每个节点都有一个父节点指针,用于表示该节点所属的集合。在带权并查集中,除了父节点指针外,每个节点还有一个权重值。这个权重值可以是任意类型的,例如整数、浮点数等,根据问题的需求而定。 带权并查集的基本操作与普通并查集类似,包括初始化、查找和合并: 1. 初始化:对于每个元素,将其视为一个独立的集合,即每个元素的父节点都是它自己,同时将权重值初始化为初始值。 2. 查找操作(Find):查找元素所属的集合,即找到元素的根节点。通过沿着父节点指针链向上遍历,直到找到根节点。返回根节点的同时可以累加路径上所有节点的权重值,以实现路径压缩和权重更新。 3. 合并操作(Merge):将两个集合合并成一个集合,即将一个集合的根节点的父节点指向另一个集合的根节点。在合并操作中,需要考虑集合的权重信息。通常,我们将权重较小的集合合并到权重较大的集合上,并更新根节点的权重值。 带权并查集的优化策略主要包括按秩合并和路径压缩。按秩合并是根据集合的秩(树的高度或节点数量)来进行合并操作,将秩较小的集合合并到秩较大的集合上,以保持树的平衡。路径压缩则是在查找操作中,将经过的每个节点直接连接到根节点,并更新路径上所有节点的权重值。 带权并查集的时间复杂度也取决于查找操作的路径长度,但由于路径压缩和按秩合并的优化,一般情况下可以达到接近常数时间复杂度。 带权并查集是一个非常有用的数据结构,可以解决一些需要考虑权重或秩的问题。通过存储额外的权重信息,并结合路径压缩和按秩合并等优化策略,可以提高算法的效率。 希望这个解释对您有所帮助!如果您还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值