标签:tar and close 解法 ring event include ... 情况
题意:一个账本记录了N个月以来的收入情况,现在有一个侦探员不同时间偷看到M段时间内的总收入,问这个账本是否为假账。
解法:带权并查集+前缀和。
判断账本真假是通过之前可算到的答案与当前读入的值是否相同来完成。那么就是只有知道新读入的区间2端的(在相同区域内的!!)前缀和才可以判断,也就是这2个端点之前被纳入了相同的区域内才可以判断。于是,我们就可以想到并查集了。(( ′? ??`) 真的么......)
假设已知x~y月的总收入为d,那么s[y]-s[x-1]=d。一般前缀和是算上自己的,这里我理解s[i]为在 i 所在的区域内 i 之前的数的大小。接着,当x,y不在相同区域内时就将其合并,在时就判断。
P.S.网上似乎还有人用查分约束的方法做。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int N=105,M=1005; 8 int n,m; 9 int fa[N],f[N]; 10 bool flag; 11 12 int ffind(int x) 13 { 14 if (fa[x]!=x) 15 { 16 int fx=fa[x]; 17 fa[x]=ffind(fx); 18 f[x]+=f[fx]; 19 } 20 return fa[x]; 21 } 22 void ins(int x,int y,int d) 23 { 24 int fx=ffind(x),fy=ffind(y); 25 if (fx!=fy) 26 { 27 fa[fx]=fy;//at ease 28 f[fx]=f[y]+d-f[x]; 29 } 30 else if (f[x]-f[y]!=d) flag=false; 31 } 32 int main() 33 { 34 int T; 35 scanf("%d",&T); 36 while (T--) 37 { 38 int x,y,d; 39 scanf("%d%d",&n,&m); 40 flag=true; 41 for (int i=0;i<=n;i++) fa[i]=i,f[i]=0; 42 for (int i=1;i<=m;i++) 43 { 44 scanf("%d%d%d",&x,&y,&d);//s[y]-s[x-1]=d 45 if (flag) ins(x-1,y,d); 46 } 47 if (flag) printf("true\n"); 48 else printf("false\n"); 49 } 50 return 0; 51 }
我再附个图好了,自己真心理解了很久很久~(┬_┬)
【bzoj 1202】[HNOI2005] 狡猾的商人(图论--带权并查集+前缀和)
标签:tar and close 解法 ring event include ... 情况
原文地址:http://www.cnblogs.com/konjak/p/6029024.html