HDU 3038How Many Answers Are Wrong(带权查并集)

How Many Answers Are Wrong

输入

10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
解释: 10个数字, 5次询问;
1 10 100 意思是1到10 的和为100
以此类推

输出

1
解释: 有一句话是错误的,

想法

1 10 100 可以看作10比1 大100 所以1要减一

在这里插入图片描述
如果想合并a, b,最终目的是求a,b,到其共同基准的距离.首先求出a, b的祖宗,即比较标准x, y,默认x认y为爹,(a的祖先认b的祖先为爹)所以a的祖先变成了y, x的祖先变成了y,所以a到a的祖先的距离(a到y)=(a到x) + (x 到y), b到y的距离即为sum[b]没变; 
下面推倒,如图
1:sum[a] = v + k;
2:sum[b] = k + (y-x);
2-1: y-x = sum[b] - sum[a] + v;
从而另sum[x] = sum[b] - sum[a] + v; 而后更新sum[a].更新的部分放在了查找中.

这里转自https://blog.csdn.net/dextrad_ihacker/article/details/51016017

主要是带权的理解。

并查集专题讲解 边带权+扩展域


这个视频里面有这个题的关键部分的理解内容。
下面代码

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2e5+5;
int f[maxn];
int num[maxn];
void init(int m)
{
	 for(int i = 0; i <= m; i ++)
 	{
		 f[i] = i;
 		 num[i] = 0;
 	}
}
int find(int x)
{
 	if(f[x] == x)
	 return x;
	 else
 	{
 		 int q = find(f[x]);
 		 num[x] += num[f[x]];
		 f[x] = q;
		 return f[x];
	 }
}
int main()
{
 int n, m;
 while(~scanf("%d%d",&n,&m))
 {
  init(n);
  int ans = 0;
  for(int i = 1; i <= m; i ++)
  {
   	 int a, b, s;
  	 scanf("%d%d%d",&a,&b,&s); 
  	 a --;//为了计算a到b的距离
  	 int a1 = find(a);
  	 int b1 = find(b);
  	 if(a1 == b1)
        {
  		  if(num[b] - num[a] != s)
  		  ans ++;
 	}
  	else
 	{
		   f[b1] = a1;
 		   num[b1] = s + num[a] - num[b];
 		   //主要是这里的理解,就在视频里面
	 }
	 }
  printf("%d\n",ans);
 }
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值