HDU- 3038 How Many Answers Are Wrong

题目链接:How Many Answers Are Wrong

题意

输入i r sum 代表 从第 i 个数 到第 r个数的和为 sum, 问你输入的总数据里有几组是矛盾的。

思路

应用带权并查集,记录每个节点到他所在树的根节点的值,代表从这个节点到根节点的这一段区间的和。 当我们输入 L ,R, SUM 时,如果root(L), root(R) 不一致,也就是说我们这个时候是判断不出来的。如果一致,那我们就看一下 val[L] - val[R] == SUM ?

在并查集中,我们在Find函数中加入了

1
2
3
4
5
6
7
8
9
10
int Find(int x)
{
if(x != f[x])
{
int t = f[x];
f[x] = Find(f[x]);
val[x] += val[t];
}
return f[x];
}

这个完成之后,val[x]就等于x这个节点到根节点的权值了。

这里画一张带权并查集的图 ,有助于理解这句话:

1
val[fa] = sum + val[b] - val[a];

最后是总代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <bits/stdc++.h>
using namespace std;
int f[200005],val[200005];
int Find(int x)
{
if(x != f[x])
{
int t = f[x];
f[x] = Find(f[x]);
val[x] += val[t];
}
return f[x];
}
int main()
{
int N, M, a, b, ans, sum;
while(scanf("%d %d",&N,&M) != EOF)
{
ans = 0;
for(int i = 0; i <= N; ++i)
{
f[i] = i;
val[i] = 0;
}
for(int i = 1; i <= M; ++i)
{
cin >> a >> b >> sum;
a--;
int fa = Find(a);
int fb = Find(b);
if(fa == fb)
{
if((val[a] - val[b]) != sum)
ans++;
}
else
{
f[fa] = fb;
val[fa] = sum + val[b] - val[a];
}
}
cout << ans << endl;
}
}