给出一个区间的长度 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;
}