【ACM回顾】并查集
以前学的不带权并查集相当简单,这次回顾主要学习一下 带权并查集
这里就要注意到并查集的本质——树,这是贯穿始终的思想
今天主要讲讲并查集的合并和路径压缩,空谈无益直接上题
A-Wireless Network (poj2236)
B-The Suspect (poj1611)
C-How Many Tables (hdu1213)
以上都是毫无营养的 不带权并查集
D-How Many Answers Are Wrong (HDU 3038)
两个人在玩一个很无聊的游戏,一个人选出数列中的一段求和并告诉对方,另一个人判断与之前给出的信息是否有矛盾
实际上sum(l,r) = presum(r) - presum(l-1),实际上表示的是第r个位置和第l-1个位置前缀和的关系
而这种关系,可以通过边权表示出来,只需要设定含义即可,此处设定为 子节点 减 父节点 之差
检验的时候,如果r和l-1属于同一个并查集,那么说明它们肯定存在某种关系(由题意这种关系已确定)
路径压缩时,只要边权能够做到等效即可,比如A连B边权为u,B连C边权为v,那么本题中含义就是B与A之差为u,C与B之差为v,那么直接把C连到A上取边权为u+v即可
getf操作在此处的作用不仅是取root,还顺便对root到当前点之间的边权进行求和,效率起见,直接把路径上的点通过递归全接到root上,只需要保证等效的边权正确即可
一点要注意,当我们合并x,y所在的两个并查集时,我们原本希望是连一条节点(l-1)到节点r的边权为sum的边
但是合并这两棵树时我们只能对根节点进行操作,f[y.root] = x.root,此处一定要区别x,y和x.root,y.root之间的区别,边权要经过换算
此处的等效边权为sum - y.edge + x.edge(类比向量的计算)
1 #include<cstdio> 2 #include<utility> 3 using namespace std; 4 5 const int N = 200010; 6 7 typedef pair<int, int> pii; 8 int n,m; 9 pii f[N]; 10 11 pii getf(int p) 12 { 13 if (f[p].first == p) 14 { 15 return pii(p,0); 16 } 17 else 18 { 19 pii retf = getf(f[p].first); 20 f[p].first = retf.first; 21 f[p].second = retf.second + f[p].second; 22 return f[p]; 23 } 24 } 25 26 int main() 27 { 28 #ifndef ONLINE_JUDGE 29 freopen("hdu3038.in","r",stdin); 30 #endif 31 while(scanf("%d %d",&n,&m) != EOF) 32 { 33 int ans = 0; 34 for(int i=0;i<=n;i++) f[i].first = i, f[i].second=0; 35 for(int i=1;i<=m;i++) 36 { 37 int l,r,sum; 38 scanf("%d %d %d",&l,&r,&sum); 39 l--; 40 pii lf = getf(l), rf = getf(r); 41 if(lf.first == rf.first) 42 { 43 if(rf.second - lf.second != sum) ans++; 44 continue; 45 } 46 f[rf.first].first = lf.first; 47 f[rf.first].second = sum - rf.second + lf.second; 48 } 49 printf("%d\n",ans); 50 } 51 return 0; 52 }
E-食物链 (poj1182)
你知道这题和上题相比最特殊的是什么吗。
它是中文的。
开玩笑的...其实一个道理。注意边权的等效,区分x和x.root的边权的意义即可
1 #include<cstdio> 2 #include<utility> 3 using namespace std; 4 5 const int N = 50000 + 10; 6 7 int n,k; 8 typedef pair<int, int> pii; 9 pii D[N]; 10 11 pii getf(int p) 12 { 13 if (D[p].first == p) 14 { 15 return pii(p, 0); 16 } 17 else 18 { 19 pii ret = getf(D[p].first); 20 D[p].first = ret.first; 21 D[p].second = (D[p].second + ret.second) % 3; 22 return D[p]; 23 } 24 } 25 26 int main() 27 { 28 #ifndef ONLINE_JUDGE 29 freopen("poj1182.in","r",stdin); 30 #endif 31 int ans = 0; 32 scanf("%d %d",&n,&k); 33 for(int i=1;i<=n;i++) D[i].first=i, D[i].second=0; 34 while(k--) 35 { 36 int opt,x,y; 37 scanf("%d %d %d",&opt,&x,&y); 38 if (x>n || y>n) 39 { 40 ans++; 41 continue; 42 } 43 pii fx = getf(x), fy = getf(y); 44 if (opt == 1) 45 { 46 if(fx.first == fy.first) 47 { 48 if(fx.second != fy.second) ans++; 49 continue; 50 } 51 D[fy.first].first = fx.first; 52 D[fy.first].second = (fx.second + 3 - fy.second) % 3; 53 } 54 if (opt == 2) 55 { 56 if(x==y) {ans++; continue;} 57 if(fx.first == fy.first) 58 { 59 if((3 + fy.second - fx.second) % 3 != 1) ans++; 60 continue; 61 } 62 D[fy.first].first = fx.first; 63 D[fy.first].second = (fx.second + 4 - fy.second) % 3; 64 } 65 } 66 printf("%d\n",ans); 67 68 return 0; 69 }