HDU 3038

给出一个区间的长度 N,及 M 个子区间和, 形如:x y z, 表示
子区间 [x, y] 的和为 z
如果一个“子区间和”与前面的“子区间和”冲突,即为错误(而且这个“子区间和”将在接下来的判断中被忽略)。
求总错误个数。

Input

有多组数据。

每组数据第一行两个整数N M (1 <= N <= 200000, 1 <= M <= 40000),
接下来每行有 M 对关系 x y z;
注:可以认为 z 为32位整型。

Output

错误个数。

Sample Input
10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1

Sample Output
1

题目大意:

给出一个长度为n的区间和5个询问,对于每个询问输入l r value 表示区间l - r 的值是value,如果这个说法和前面发生冲突则记录下来,比如前面说过的是【3,4】的值是20,而【1,4】的值是30,那么【1,2】的值一定是10,如果不是10则说明发生了冲突,输出冲突的个数。

解题思路:

经典带权并查集,因为这道题涉及到区间问题,我们需要把闭区间弄成开区间,比如[1,4]实际上是(0,4],因为后面要涉及到区间和并,通过观察发现,(0,4] = 30,(2,4]的值是20,他们共同的右边端点的值是4,当下一个区间是 (0,2]时,左右区间端点都和4建立了关系才能判断冲突,因此只有区间两端的根节点一致时,才可以判断冲突是否发生,如果根节点不同,则把左端点并入右端点的区间,同时更新一下右端点根节点的权值。AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 2e5+50;
typedef long long ll;
int f[N], sum[N], n, m, ans;
int find(int x)
{
	if (f[x] == x)
	  return x;
	int t = f[x];
	f[x] = find(f[x]);
	sum[x] += sum[t];
	return f[x];
}
void init()
{
	for (int i = 0; i <= n; i ++)
	    f[i] = i;
	memset(sum, 0, sizeof sum);
}
int main()
{
	while (cin >> n >> m)
	{
		ans = 0;
		init();
		while (m --)
		{
			int x, y, z;
			cin >> x >> y >> z;
			x--;
			int t1 = find(x);
			int t2 = find(y);
			if (t1 == t2)
			{
				if (sum[x] - sum[y] != z)
				  ans++;
			}
			else
			{
				f[t1] = t2;
				sum[t1] = -sum[x] + sum[y] + z;
			}
		}
		cout << ans <<endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Hayasaka/p/14294206.html