hdu 3038(扩展并查集)
2016-03-27 22:10
218 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3038
题意:给出区间[1,n],下面有m组数据,l r v区间[l,r]之和为v,每输入一组数据,判断此组条件是否与前面冲突 ,最后输出与前面冲突的数据的个数.
比如 [1 5]区间和为100 然后后面给出区间[1,2]的和为 200 那肯定就是有问题的了。
极力推荐这位大牛的博客:/article/2390628.html
这题让我学到了很多,特别是关于向量偏移,可以直接找到根节点与子节点的关系
这题我们利用一个sum[]数组保存从某点到其祖先节点距离。
1.从上图我们可以看出,当roota!=rootb时 如果将roota并入rootb,那么是不是 roota->rootb = b->rootb - b->roota
然后我们可以知道 b->roota = a->roota - a->b
所以最后可以推出 roota ->rootb = b->rootb + a->b - a->roota
而roota的根节点是rootb,所以 roota->rootb = sum[roota]
然后依次推出得到 sum[roota] = -sum[a]+sum+v (这里的a要说明一下由于是区间 [a,b] ,[a,b] = [root,b]-[root,a-1],所以a要减一)
2.如果roota==rootb 是不是 a和b的根节点已经相同了?所以我们只要验证 a->b是否与题中的长度一致了。
所以[b] a->b = a->root - b->root
然后得到表达式 v = sum[a]-sum[b] (一定要记住这里的sum都是相对于根节点的,sum的更新在路径压缩的时候更新了)
这样说是不是懂了向量偏移的思想呢??
下面上代码:
题意:给出区间[1,n],下面有m组数据,l r v区间[l,r]之和为v,每输入一组数据,判断此组条件是否与前面冲突 ,最后输出与前面冲突的数据的个数.
比如 [1 5]区间和为100 然后后面给出区间[1,2]的和为 200 那肯定就是有问题的了。
极力推荐这位大牛的博客:/article/2390628.html
这题让我学到了很多,特别是关于向量偏移,可以直接找到根节点与子节点的关系
这题我们利用一个sum[]数组保存从某点到其祖先节点距离。
1.从上图我们可以看出,当roota!=rootb时 如果将roota并入rootb,那么是不是 roota->rootb = b->rootb - b->roota
然后我们可以知道 b->roota = a->roota - a->b
所以最后可以推出 roota ->rootb = b->rootb + a->b - a->roota
而roota的根节点是rootb,所以 roota->rootb = sum[roota]
然后依次推出得到 sum[roota] = -sum[a]+sum+v (这里的a要说明一下由于是区间 [a,b] ,[a,b] = [root,b]-[root,a-1],所以a要减一)
2.如果roota==rootb 是不是 a和b的根节点已经相同了?所以我们只要验证 a->b是否与题中的长度一致了。
所以[b] a->b = a->root - b->root
然后得到表达式 v = sum[a]-sum[b] (一定要记住这里的sum都是相对于根节点的,sum的更新在路径压缩的时候更新了)
这样说是不是懂了向量偏移的思想呢??
下面上代码:
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; const int N =200010; int father ; int sum ; ///记录当前结点到根结点的距离 int _find(int x){ if(x!=father[x]){ int t = father[x]; father[x] = _find(father[x]); sum[x]+=sum[t]; } return father[x]; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF){ for(int i=0;i<=n;i++){ father[i] = i; sum[i] = 0; } int ans = 0; while(m--){ int a,b,v; scanf("%d%d%d",&a,&b,&v); a--; int roota = _find(a); int rootb = _find(b); if(roota==rootb){ if(sum[b]-sum[a]!=v) ans++; ///精华部分1 } else{ father[roota] = rootb; sum[roota] = -sum[a]+sum[b]+v; ///精华部分2 } } printf("%d\n",ans); } return 0; }
相关文章推荐
- 更新丢失问题
- C++ const的各种用法
- Xcode安装XAlign
- 结对项目预热
- HTML5 的 localStorage(本地数据库) 的用法
- bios 关机过程
- Java基础之String,StringBuilder,StringBuffer
- leetcode118. Pascal's Triangle
- object常用方法与包
- 背包问题
- 20145204 《Java程序设计》第四周学习总结
- [基础] Loss function(一)
- 8.3 fileinput--多文件输入操作
- 8.3 fileinput--多文件输入操作
- iOS打包(ipa包)
- PAT甲级1007. Maximum Subsequence Sum (25) (vector)
- 【分享】PotPlayer播放器【整合硬盘版】[带LAV0.68+madVR0.90.13+234皮肤+OpenCodec解码+DSP插件++mad设置注册表+电视直播+免设置&卸载补丁]
- Leetcode #25 Reverse Nodes in k-Group K区间链表交换 解题报告
- 提取Chrome插件为crx文件
- win7win8 64位汇编开发环境合集安装与设置