hdu4313 树上有一些特殊点,使这些特殊点不连通至少需要割掉多少边权 并查集/类似kruskal
想了一会突然想到蓝桥杯最后一题,用了和那题类似的技巧处理,当时写完还自我陶醉了一下,虽然只能过小数据,但我过得姿势好看哇==
将边权从大到小排序,然后开始加边,开了一个vis数组(就是这个数组)表示这个集合为真或者假
真表示集合内有特殊点,反之无,只要出现两边都为真就ans+该边,vis伴随集合并相应的传递
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 int father[100005],vis[100005]; 7 struct dian{ 8 int l,r,w; 9 }a[100005]; 10 int cmp(dian n1,dian n2) 11 { 12 return n1.w>n2.w; 13 } 14 int find(int x) 15 { 16 if (father[x]!=x) father[x]=find(father[x]); 17 return father[x]; 18 } 19 int main() 20 { 21 int T,n,m,i,f1,f2,x; 22 long long ans; 23 scanf("%d",&T); 24 while (T--) 25 { 26 scanf("%d%d",&n,&m); 27 for (i=1;i<n;i++) 28 scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w); 29 sort(a+1,a+n,cmp); 30 for (i=0;i<n;i++) father[i]=i; 31 memset(vis,0,sizeof(vis)); 32 for (i=1;i<=m;i++) 33 { 34 scanf("%d",&x); 35 vis[x]=1; 36 } 37 ans=0; 38 for (i=1;i<n;i++) 39 { 40 f1=find(a[i].l); f2=find(a[i].r); 41 if (vis[f1]&&vis[f2]) ans=ans+a[i].w; 42 father[f1]=f2; 43 vis[f2]|=vis[f1]; 44 } 45 //for (i=0;i<n;i++) printf("%d ",vis[i]); printf("\n"); 46 printf("%lld\n",ans); 47 } 48 return 0; 49 }