题目链接: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; } }
|