带权并查集(深度理解)

我们都知道一个点的权值,是这个节点到根节点之间的差值,我们根据差值,就可以知道很多东西,权值数组sum[maxn]

1.已知两个点的权值(假设都是与根节点的权值),那么这个两个点的差值为   sum[x]-sum[y]=(fen[x]-u)-(fen[y]-u)=fen[x]-fen[y] 就是参考点变换了一下,就可以间接找出这两个节点之间的差值。

2.在合并两个点时,  我们已经知道了,这个权值就是这个点与根节点之间的差值。我们可以根据这个关系,在合并集合的时候,找出两个集合的根节点之间的差值。

我们现在假设定义 pre[fy]=fx 就是将fy连到fx上,我们 就定义fy 比 fx 高多少x(或者高 -x ),然后pre[fx]=fy 就是fx 比fy 高什么。我们都先定义一个方向,在后面好理解 权值之间来回的关系。上面 第一条已经说了,权值就是将参照点变了一下,我们 通常x比y高,也可以间接的来说,x先比a高 10分,a又比b高10分,b又比c高 10分 ,c又比y高10分,现在我们定义一个方向矢量,由x直接到y的那个矢量就是由x到a再到b再到c最后再到y,那么这个值全加上,就是x直接与y之间的 差值(就是权值40),我们可以利用这个性质,可以来理解带权并查集中的难点。

就是下面这个地方容易搞混,其实将方向矢量加入到这个思考中,就会想的简单一点,我们现在已经都设置了方向,由px->py ,就是px比py 高多少,py->px 就是py比px 高多少(也是权值之间的差值),所以下面这些式子都是根据在这个方向的确立之上的,由x直接到px ,等价于由x间接到y->py->px,这样将中间步骤的差值都加上去,就可以找出 px->py 之间差值,或者py->px 之间差值。

 

void join(int x,int y,int s)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy)
	{
		pre[fy]=fx;
		sum[fy]=sum[x]-sum[y]-s;
		
		//pre[fx]=fy;
		//sum[fx]=-sum[x]+sum[y]+s;
	}
}
//不管上面是谁指向谁,下面求出这个a,b之间差值都是这样求得,不用改变。毕竟我们已经指定 a->b了。
scanf("%d%d",&a,&b);
int fa=find(a);
int fb=find(b);
if(fa!=fb)
	cout<<"-1"<<endl;
else
{
	cout<<sum[a]-sum[b]<<endl;
}

真的是很巧妙。

分数调查

HihoCoder - 1515    

Zjnu Stadium

HDU - 3047

How Many Answers Are Wrong

HDU - 3038

都会涉及这个应用,是很重要的一个结论吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值