HDU 3038 How Many Answers Are Wrong【带权并查集】

HDU 3038 How Many Answers Are Wrong

原题链接: vjudge传送门

题目大意:
有N个数,不知道它们具体的值,但是知道某两个数之间(包括这两个数)的所有数之和,
给出M个区间即区间和,需要判断有多少个区间和与前边已知的区间和存在矛盾。
例如给出区间和[1,5]为30,[3,5]为15,再给出[1,3]为20,显然[1,3]的值应该为30-15=15,故该答案错误,需求解错误答案个数
(需把闭区间看成半开半闭区间理解)

具体思路:
带权并查集,我也是第一次接触,看了题解也看了好半天
给定一个区间,若区间两端点是同一集合,判断是否区间和是否与已知矛盾,若不矛盾则把两个端点加入同一集合
若两个端点不是同一集合,直接合并集合。

DaLao的题解https://cloud.tencent.com/developer/article/1073376 ,Orz

令sum[x]表示区间[x,f[x]]的和,这个可以在路径压缩的时候更新,
对于一组数据(u,v,w),令r1=Find(u),r2=Find(v),
于是若r1= =r2,此时u,v就有了相同的参考点,而sum[u]为区间[u,r1(r2)]的和,sum[v]为区间[v,r2(r1)]的和,
于是只需判断w= =sum[v]-sum[u]即可;
若r1<r2,此时可以分为两种情况,
(u,v,r1,r2)或者(u,r1,v,r2),
对于情况1来说,此时father[r1]=r2,sum[r1]=sum[v]-(sum[u]-w);
根据坐标轴(u,v,r1,r2)就可以理解:sum[r1]=sum[v]-(sum[u]-w)

  • r1+…+r2 =sum[r1]
  • sum(u)=u+…+r1
  • sum(v)=v+…+r2
  • w=u+…+v,
    将上式代入即可

对于情况2有sum[r1]=w-sun[u]+sum[v].
通过观察,我们可以发现情况1和情况2的结果是一样的,于是可以合并。
同理,对于r1>r2这种情况也一样,这里就不在赘述了。

具体代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const MAXN = 2e5 + 10;
int sum[MAXN], fa[MAXN];	//sum[i]代表从第i位加到第fa[i]位的和
int n, m;
void init() {
	memset(sum, 0, sizeof(sum));
	for (int i = 0; i <= n; i++)
		fa[i] = i;
}
int find(int x)
{
	if (x == fa[x])
		return x;
	int tmp = fa[x];	//路径压缩时顺便更新sum数组
	fa[x] = find(fa[x]);
	sum[x] += sum[tmp];
	return fa[x];
}
bool Union(int u, int v, int w)
{
	int r1 = find(u);
	int r2 = find(v);
	if (r1 == r2) {
		if (sum[u] == w + sum[v])
			return true;
		return false;
	}
	else {	//不在同一集合
		fa[r1] = r2;	//合并集合
		sum[r1] = sum[v] - sum[u] + w;	//更新sum数组
		return true;
	}
}
int main()
{
	int u, v, w, ans;
	while (~scanf("%d%d", &n, &m)) 
	{
		init();
		ans = 0;
		while (m--) 
		{
			scanf("%d%d%d", &u, &v, &w);
			if (!Union(u - 1, v, w))ans++;	//注意此处u要减1
		}
		printf("%d\n", ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值