[并查集][排序] Jzoj P2940 生成输入数据
题解
- 题目大意:给定一棵最小生成树,问它的完全图的最小边权和为多少
- 我们可以先把每条边的权值从小到大排序
- 然后把n个点拆出来,再把n个点打入到最小生成树中
- 那么对于新加的一条边,它对答案的贡献显然就是(size[u]+size[v]-1)*(dis[u][v]+1)
- 因为完全图中两两点要有一条边相连,而且又不能改变给定的最小生成树,那么两点子树点两两相连,距离就是两点距离+1
代码
1 #include <cstdio> 2 #include <algorithm> 3 #define N 20020 4 #define ll long long 5 using namespace std; 6 struct edge { ll x,y,v; }e[N]; 7 ll T,n,fa[N],size[N],ans; 8 bool cmp(edge a,edge b) { return a.v<b.v; } 9 ll getfather(ll x) { return (fa[x]==x)?x:fa[x]=getfather(fa[x]); } 10 int main() 11 { 12 scanf("%lld",&T); 13 while (T--) 14 { 15 scanf("%lld",&n); 16 for (ll i=1;i<n;i++) scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].v); 17 for (ll i=1;i<=n;i++) fa[i]=i,size[i]=1; 18 sort(e+1,e+n,cmp),ans=0; 19 for (ll i=1;i<n;i++) 20 { 21 ll u=getfather(e[i].x),v=getfather(e[i].y); 22 if (u!=v) ans+=(size[u]*size[v]-1)*(e[i].v+1),size[u]+=size[v],fa[v]=u,ans+=e[i].v; 23 } 24 printf("%lld\n",ans); 25 } 26 }