带权并查集 - HDU 3038
2017-08-18 13:27
375 查看
题意
给出一些询问区间和询问结果,结果是询问区间内所有数的和,如果新一条询问的结果与原来的结果有冲突,则记录询问结果错误。问询问结果错误的数目。将区间 [a,b] 内数的和 转化为 b的前缀和 - (a-1)的前缀和。
保持并查集的祖先树的树根在该树中序号最低的位置,这样一个树中节点到树根的每一段距离的和即为 [树根的序号,该节点序号] 的数的和
每次检查新的查询会不会与之前构建的带权并查集冲突,如果不冲突就加入到并查集中
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <queue> using namespace std; typedef long long LL; const int inf=0x3f3f3f3f; const double eps=1e-8; const int maxn=200005; int n,m; int f[maxn],sum[maxn]; int _find(int x){ if(x!=f[x]){ int df=f[x]; f[x]=_find(f[x]); sum[x]+=sum[df]; } return f[x]; } bool _merge(int u,int v,int d){ int fu=_find(u),fv=_find(v); if(fu==fv){ if(sum[v]-sum[u]!=d){return false;} } else if(fu>fv){ f[fu]=fv; sum[fu]=sum[v]-sum[u]-d;//两种情况下对距离更新的方法不同 } else { f[fv]=fu; sum[fv]=sum[u]-sum[v]+d; } return true; } void init() { for(int i=0;i<=n;++i){ f[i]=i; } memset(sum,0,sizeof(sum)); } int main() { while(~scanf("%d%d",&n,&m)){ init(); int a,b,c,ans=0;; for(int i=0;i<m;++i){ scanf("%d%d%d",&a,&b,&c); a--; if(!_merge(a,b,c))ans++; } //debug(f,12); //debug(sum,12); printf("%d\n",ans); } }
相关文章推荐
- How Many Answers Are Wrong HDU - 3038 (并查集)题解
- hdu 3038 How Many Answers Are Wrong(种类并查集)2009 Multi-University Training Contest 13
- HDU 3038 带权并查集
- HDU 3038 How Many Answers Are Wrong (并查集)
- HDU 3038 How Many Answers Are Wrong 带权并查集
- hdu 3038 How Many Answers Are Wrong(带权并查集)
- HDU 3038 带权并查集,区间
- hdu 3038 How Many Answers Are Wrong 带权并查集
- hdu 3038 How Many Answers Are Wrong 带权并查集
- 并查集【路径迭代】HDU 3038 How Many Answers Are Wrong
- HDU 3038 How Many Answers Are Wrong(带权并查集)
- hdu 3038 How Many Answers Are Wrong——带权并查集
- hdu 3038 How Many Answers Are Wrong(带权并查集)
- kuangbin专题五: D - How Many Answers Are Wrong HDU - 3038 (带权并查集)
- HDU 3038 带权并查集,区间
- hdu 3038(带权并查集)
- hdu 3038 带权并查集
- hdu 3038 How Many Answers Are Wrong(带权并查集+树的性质)
- HDU 3038 How Many Answers Are Wrong 带权并查集
- hdu-3038 带权并查集