前言

如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。

带权并查集详解:

首先讨论一下带权并查集的主要功能。并查集主要是维护不同元素之间传递关系的数据结构,如果不带权,那么维护的就是不同元素是否属于同一个集合,即连通关系。如果带权,那么除了维护连通性之外,还会维护同一个集合中各个元素之间的关系。

对于带权并查集的具体实现,最重要的维护元素是 d[x]d[x]d[x],表示元素 xxx 到根节点 rootrootroot 的偏移量,即 d[x]=x→rootd[x] = x \rightarrow rootd[x]=x→root,而这个偏移量是由我们自己定义的,取决于具体题意。

接下来我们通过一道例题,HDU3038HDU\ 3038HDU 3038 来仔细讲解这个数据结构。


题意:

一个长度为 nnn 个序列,一共 mmm 个询问。每次询问给出 l,r,suml,r,suml,r,sum,表示这个序列中区间 [l,r][l,r][l,r] 的 sumsumsum 和。 问一共有几组询问与前面为真的询问不符,如果该组询问不符合事实,忽略这组询问。


思路:

很明显,这题主要维护序列上每个节点之间的连通关系,以及节点之间的偏移量。我们定义 d[x]=x→root=sum[root]−sum[x]d[x] = x\rightarrow root = sum[root]-sum[x]d[x]=x→root=sum[root]−sum[x],即区间 [x+1,root][x+1, root][x+1,root] 的和。这里有一个需要注意的地方,我们不能令 d[x]=x→root=[x,root]d[x] = x\rightarrow root = [x, root]d[x]=x→root=[x,root] 区间和,因为 d[x]d[x]d[x] 初始化时为 000,而如果是 [x,root][x,root][x,root] 的区间和,那么初始化时 d[x]=a[x]=[x,x]d[x] = a[x] = [x,x]d[x]=a[x]=[x,x] 区间和,而不是000,因此会发生错误。所以我们维护的是 d[x]=x→root=sum[root]−sum[x]d[x] = x\rightarrow root = sum[root]-sum[x]d[x]=x→root=sum[root]−sum[x]。

然后我们再来考虑并查集的路径压缩操作。并查集的本质是一颗森林,带权并查集增加的操作就是增加了边权。

现在我们来考虑下面的这个图,执行 find(B)find(B)find(B) 的过程,fa[B]=find(fa[B])fa[B] = find(fa[B])fa[B]=find(fa[B]),就可以将 BBB 连向 rootrootroot,但是我们需要更新 d[B]d[B]d[B],d[B]=B→root=B→A+A→rootd[B] = B\rightarrow root=B\rightarrow A\ +\ A\rightarrow rootd[B]=B→root=B→A + A→root,而在路径压缩之前,d[B]=B→Ad[B] = B\rightarrow Ad[B]=B→A。因此路径压缩时,d[B]=d[B]+d[A]d[B] = d[B]+d[A]d[B]=d[B]+d[A],也可以理解为边权相加。

int find(int x){if(fa[x]==x) return x;int root = find(fa[x]);d[x] += d[fa[x]], fa[x] = root;return fa[x];
}


现在我们开始做这道题目。首先初始化,fa[i]=i,d[i]=0fa[i] = i, \ d[i] = 0fa[i]=i, d[i]=0,然后对于每个 [a,b]=sum,sum[b]−sum[a−1]=sum[a,b] = sum,sum[b]-sum[a-1] = sum[a,b]=sum,sum[b]−sum[a−1]=sum,我们先判断 a−1a-1a−1 与 bbb 是否在同一个集合内。

①①① 如果不在同一个集合内,则说明 a−1a-1a−1 与 bbb 没有偏移关系,因此我们需要将这两个集合进行合并,存入他们的偏移关系,令fa=find(a−1),fb=find(b)fa = find(a-1),fb = find(b)fa=find(a−1),fb=find(b)。(a−1)→b=(a−1)→fa+fa→fb+fb→b=sum=d[a−1]+d[fa]−d[b](a-1)\rightarrow b = (a-1)\rightarrow fa\ +\ fa\rightarrow fb \ + \ fb\rightarrow b = sum = d[a-1]+d[fa]-d[b](a−1)→b=(a−1)→fa + fa→fb + fb→b=sum=d[a−1]+d[fa]−d[b],而此处的 d[fa]d[fa]d[fa] 就是合并之后,fafafa 对于 fbfbfb 的偏移量。

②②② 如果在同一个集合中,则判断 (a−1)→b=(a−1)→root+root→b=d[a−1]−d[b](a-1)\rightarrow b = (a-1)\rightarrow root\ + \ root \rightarrow b=d[a-1]-d[b](a−1)→b=(a−1)→root + root→b=d[a−1]−d[b] 是否等于 sumsumsum,如果不等于,则为假。

到此,这题就可以解决了。最后回顾一下带权并查集,带权并查集的核心就是维护多个元素之间的连通以及偏移关系,甚至可以维护多个偏移关系,而偏移的东西可以理解为当前节点到根节点的边长之和。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 2*1e5+1000;int fa[N],d[N],n,m;int find(int x){if(fa[x]==x) return x;int root = find(fa[x]);d[x] += d[fa[x]], fa[x] = root;return fa[x];
}int main()
{while(~scanf("%d%d",&n,&m)){rep(i,0,n) fa[i] = i, d[i] = 0;int ct = 0;rep(i,1,m){int a,b,c; scanf("%d%d%d",&a,&b,&c); a--;int f1 = find(a), f2 = find(b);if(f1 == f2){if(d[a]-d[b] != c) ct++;}else{fa[f1] = f2, d[f1] = c+d[b]-d[a];}}printf("%d\n",ct);}return 0;
}

【带权并查集详解】以HDU 3038为例【How Many Answers Are Wrong】相关推荐

  1. BZOJ.4500.矩阵(差分约束 SPFA判负环 / 带权并查集)

    BZOJ 差分约束: 我是谁,差分约束是啥,这是哪 太真实了= = 插个广告:这里有差分约束详(并不)解. 记\(r_i\)为第\(i\)行整体加了多少的权值,\(c_i\)为第\(i\)列整体加了多 ...

  2. 【无码专区9】序列统计(带权并查集 + 前缀和建边 + dp)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  3. 2017乌鲁木齐区域赛I(带权并查集)

    #include<bits/stdc++.h> using namespace std; int f[200010];//代表元 long long rl[200010];//记rl[i] ...

  4. BZOJ 2303 方格染色(带权并查集)

    要使得每个2*2的矩形有奇数个红色,如果我们把红色记为1,蓝色记为0,那么我们得到了这2*2的矩形里的数字异或和为1. 对于每个方格则有a(i,j)^a(i-1,j)^a(i,j-1)^a(i-1,j ...

  5. POJ1703带权并查集(距离或者异或)

    题意:       有两个黑社会帮派,有n个人,他们肯定属于两个帮派中的一个,然后有两种操作 1 D a b 给出a b 两个人不属于同一个帮派 2 A a b 问a b 两个人关系 输出 同一个帮派 ...

  6. POJ1988(带权并查集,搬砖块)

    题意:        可以这样理解,有n快方形积木,一开始都是单独的放到哪,然后有两种操作 1 M a b 把a所在的那一堆落到b所在那一堆的上面(一开始自己是一堆) 2 C a 问a下面有多少个积木 ...

  7. LA3027简单带权并查集

    题意:       有n个点,一开始大家都是独立的点,然后给出一些关系,a,b表示a是b的父亲节点,距离是abs(a-b)%1000,然后有一些询问,每次询问一个节点a到父亲节点的距离是多少? 思路: ...

  8. hdu3234 带权并查集(XOR)

    题意:       给你n个未知的正整数,有三总操作       I P V            P的值是V       I P Q V          P XOR Q = V       Q K ...

  9. hdu4829 带权并查集(题目不错)

    题意: Information Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...

  10. poj1182 and 携程预赛2第一题 带权并查集

    题意:       动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.  现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底 ...

最新文章

  1. 什么是Bootstrap Aggregating
  2. Tidio AI 趋势报告:约42%受访者能够接受机器人伴侣
  3. IntelliJ IDEA 2020.2 EAP 5 发布:完美支持Java 15
  4. 【PC工具】数学公式编辑器MathType v7.4.4.516你懂的版本
  5. linux网络存储服务器选题意义,基于嵌入式Linux的网络存储的实现和研究
  6. 基于android的lbs技术,基于Android的LBS应用研究
  7. Python集合常用函数使用详解(内附详细案例)
  8. [数分提高]2014-2015-2第6教学周第2次课讲义 3.4 导数的综合应用
  9. 一篇博客:分类模型的 Loss 为什么使用 cross entropy 而不是 classification error 或 squared error...
  10. UEditor 百度Web编辑器 - JSP版本的使用
  11. 硬件科普系列之硬盘——总线、协议、接口和固态硬盘篇
  12. CFA要学哪些课程?零基础怎么学CFA呢?
  13. arm linux 看库的依赖,Linux命令查看X86平台 ARM平台上可执行文件与库的依赖关系...
  14. 阿里云服务器搭建ftp服务器
  15. 飞鸽传书2014绿色版
  16. html可以用搜狗浏览器打开网页,搜狗浏览器网页不小心关了怎么办?搜狗浏览器恢复页面三种方法...
  17. 黑洞照片打印是用超级计算机,给黑洞冲洗一张照片,怎么就用了两年时间 | 科技向未来...
  18. Git在windows和linux安装教程
  19. 乘风领航、耀世创新——DEFI平台Lizard打造数字金融新世界
  20. 21 Excel动态图表实现原理

热门文章

  1. CentOS 6.5 shell中su切换自动输入密码
  2. 我对Backbone的认识
  3. python-socket模块基本用法收集
  4. Firefox和Chrome的选择
  5. 为多个VLAN实现DCHP
  6. linux mysql配置_Linux下MySQL安装配置 MySQL配置参数详解
  7. SSM 实现 RESTful 风格
  8. OpenCV-图像处理(28、轮廓发现(find contour in your image))
  9. python程序设计第二版课后答案江红_Python核心编程第二版 第十三章课后答案
  10. matlab怎么调出来的,如何调出MATLAB内部函数的源程序?