HDU 3038 How Many Answers Are Wrong(带权并查集)
太坑人了啊,读入数据a,b,s的时候,我刚开始s用的%lld,给我WA。 实在找不到错误啊,后来不知怎么地突然有个想法,改成%I64d,竟然AC了
思路:我建立一个sum数组,设i的父亲为fa,sum[i]表示(fa,i]中的数的和(不包括fa,包括i),
合并的时候,不是合并a,b,而是合并a-1,b。这样做的目是因为s是[a,b]的和,如果直接合并a,b,那么按照我数组的定义应该是(a,b]的和,这样不符合题意。
接下来,每次读入a,b,只要根据他们父节点的不同情况分类讨论即可。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxn=200010; int father[maxn]; long long sum[maxn]; //设i的父亲为fa,sum[i]表示(fa,i]中的数的和(不包括fa,包括i) int n,m; void init() { for(int i=0; i<=n; i++) { father[i]=i; sum[i]=0; } } int find_root(int x) { if(father[x]==x) return x; int fa=father[x]; father[x]=find_root(father[x]); sum[x]=(sum[x]+sum[fa]); return father[x]; } //合并的时候,保证x<y void Union(int x,int y) { father[y]=x; } int main() { int a,b,ans=0; long long s; while(scanf("%d%d",&n,&m)!=EOF) { init(); //怎么老忘记写这个啊 ans=0; for(int i=1; i<=m; i++) { scanf("%d%d%I64d",&a,&b,&s); //就是这里,本来用的是lld的格式,导致WA int fa=find_root(a-1); int fb=find_root(b); /* fa=fb时,(fa,a-1]=sum[a-1],(fb,b]=sum[b], ——>[a,b]=sum[b]-sum[a-1],显然即应该等于s 若不等于,即使错误的 */ if(fa==fb) { if(sum[b]-sum[a-1]!=s) { ans++; } } else { if(fb>a-1) { /* 大小关系:fa<=a-1<fb<=b (fa,a-1]=sum[a-1],[a,b]=s,(fb,b]=sum[b]; ——>[a,fb]=s-sum[b], (fa,fb]=(fa,a-1]+[a-1,fb]=sum[a-1]+s-sum[b]; */ Union(fa,fb); //更新fb的父节点fa到fb区间的和(不包括fa) sum[fb]=sum[a-1]+s-sum[b]; } else if(fb==a-1) { /* 大小关系:fa<=a-1=fb<=b (fa,a-1]=sum[a-1],[a,b]=s,(fb,b]=sum[b]; ——>sum[b]即为[a,b]的和。 若sum[b]不等于s,说明错误 如果相同,则合并 */ if(s!=sum[b]) { ans++; } else { Union(fa,fb); sum[fb]=sum[a-1]; } } //fb<a-1 else { if(fb>fa) { /* 大小关系:fa<fb<a-1<b (fb,b]=sum[b],(a-1,b]=s ——>(fb,a-1]=sum[b]-s; 再由(fa,a-1]=sum[a-1]——>(fa,fb]=sum[a-1]-sum[b]+s; */ Union(fa,fb); sum[fb]=sum[a-1]-sum[b]+s; } else { /* 大小关系:fb<fa<=a-1<=b (fb,b]=sum[b],(a-1,b]=s,(fa,a-1]=sum[a-1]; ——>(fa,b]=s+sum[a-1] ——>(fb,fa]=sum[b]-s-sum[a-1]; */ Union(fb,fa); sum[fa]=sum[b]-s-sum[a-1]; } } } } printf("%d\n",ans); } return 0; }