题意:给出一棵树,定义两点间代价为两点路径上最长的边权,问任两点间的代价和。
解法:这道题的解法十分巧妙:直接用Kruskal对这棵树求最小生成树,然后对于即将加入到MST的这条边(u,v,w),这条边对答案的贡献是size[u]*size[v]*w。为什么?因为我们是从小到大把边加入,所以对于两点分别位于u联通块和v联通块的路径上最长的边必定是(u,v,w),所以求完MST之后就是答案了。
#include<bits/stdc++.h> using namespace std; typedef unsigned long long uLL; const int N=1e6+10; int T,n,fa[N],size[N]; struct edge{ int x,y,z; bool operator < (const edge &rhs) const { return z<rhs.z; } }e[N]; int getfa(int x) { return x==fa[x] ? x : fa[x]=getfa(fa[x]); } int main() { int T; cin>>T; while (T--) { scanf("%d",&n); for (int i=1;i<n;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); sort(e+1,e+n); for (int i=1;i<=n;i++) fa[i]=i,size[i]=1; uLL ans=0; for (int i=1;i<n;i++) { int fx=getfa(e[i].x),fy=getfa(e[i].y); if (fx==fy) continue; ans+=(uLL)e[i].z*size[fx]*size[fy]; size[fx]+=size[fy]; fa[fy]=fx; } printf("%llu ",ans); } return 0; }