HDU-3038 How Many Answers Are Wrong (带权并查集)
题意:给出区间[1,n],m个条件:[u,v]的和为w,求有几条与前面的条件矛盾
数据范围:1 <= n <= 2e5,m <= 40000
终于看懂了啊。。。之前一直没弄懂,问了大佬也没问明白我觉得这题目纠结和别扭的点。
推荐一篇博客:https://www.cnblogs.com/liyinggang/p/5327055.html
之前我看不懂的时候也在看这篇,现在看懂也是在这篇,解释得真的很棒,感谢作者
就我自己卡住的点解释一下:这题给的是区间,我没想明白怎么处理这个区间矛盾关系,专题又告诉我这是并查集,于是被带入了“把区间放进并查集???”的误区,虽然我自己也觉得这样的脑洞不靠谱。。。实际上先不看w这个值,像我们最开始学习的并查集处理连接关系那样,还是把u,v两个点(或它们的根结点)(而不包括中间的)连在一起,我们需要处理的问题是:怎样通过u->root_u,v->root_v确定u->v的值,上面的博客用向量偏移的思想讲得很清楚,把并查集的边看作向量,通过向量加减法,就能求出u->v,如果u->v在不合并时就已经存在,就可以判断对错了。
再联系一下并查集的作用:快速判断两个点是否是同一集合,快速合并两个集合
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 5 const int mx = 2e5+10; 6 int sum[mx], pa[mx]; 7 8 int fx(int x) { 9 if (x != pa[x]) { 10 int t = pa[x]; 11 pa[x] = fx(pa[x]); 12 sum[x] += sum[t]; 13 } 14 return pa[x]; 15 } 16 17 int main() { 18 int n, m; 19 while (scanf("%d%d", &n, &m) == 2) { 20 int ans = 0; 21 for (int i = 0; i <= n; i++) { 22 pa[i] = i; 23 sum[i] = 0; 24 } 25 while (m--) { 26 int u, v, w; 27 scanf("%d%d%d", &u, &v, &w); 28 u--; 29 int a = fx(u), b = fx(v); 30 if (a != b) { 31 pa[a] = b; 32 sum[a] = sum[v]-sum[u]+w; 33 } 34 else if (sum[u]-sum[v] != w) ans++; 35 } 36 printf("%d\n", ans); 37 } 38 return 0; 39 }