解题思路
感觉这道题就是题意太难理解了,因为我真的菜 理解之后还是很容易的。
我们每次考虑到第 i i i 条边 ( x , y , w ) (x,y,w) (x,y,w),假设这之前的 i − 1 i-1 i−1 条边已经构造好了若干个都是完全图的联通块,并且 T T T 中的前 i − 1 i-1 i−1 条边就是这些联通块的生成树(也就是保证了 Kruskal 算法前 i − 1 i-1 i−1 步都选的是 T T T 中的边)。
在连上 ( x , y , w ) (x,y,w) (x,y,w) 之前, ( x , y ) (x,y) (x,y) 应该分在两个联通块里。我们把 ( x , y , w ) (x,y,w) (x,y,w) 连起来之后,对于两个联通块里除了 ( x , y ) (x,y) (x,y) 以外的所有点对,都连一条权为 w + 1 w+1 w+1 的边。这样,显然在 Kruskal 算法的第 i i i 步中,选的是第 i i i 条边(因为现在只剩下两个联通块连接,除了 ( x , y , w ) (x,y,w) (x,y,w) 之外所有的边权都 ≥ w \ge w ≥w,肯定得选 ( x , y , w ) (x,y,w) (x,y,w))
所以我们把 T T T 中的边按边权排序,并查集合并的时候记录一下联通块大小。然后 ( x , y , w ) (x,y,w) (x,y,w) 这条边的贡献就是 ( c n t [ u ] × c n t [ v ] − 1 ) × ( w + 1 ) (cnt[u]\times cnt[v]-1)\times (w+1) (cnt[u]×cnt[v]−1)×(w+1)
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
using namespace std;
int t,fa[100010];
long long ans,cnt[100010];
struct c{
int x,y;
long long w;
}a[100010];
int find(int x) {
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
bool cmp(c l,c r)
{
return l.w<r.w;
}
int main(){
scanf("%d",&t);
for(int i=1;i<=t-1;i++)
scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].w);
sort(a+1,a+t,cmp);
for(int i=1;i<=t;i++)
cnt[i]=1,fa[i]=i;
for(int i=1;i<=t-1;i++)
{
int x=find(a[i].x),y=find(a[i].y);
ans=ans+(cnt[x]*cnt[y]-1)*(a[i].w+1);
ans+=a[i].w;
fa[x]=y;
cnt[y]+=cnt[x];
}
printf("%lld",ans);
}