每次新边的权值,一定是当前枚举出的边的权值加上1,不然会破坏原最小生成树。
开辟一个s数组维护连同块中点的数量,合并两个连通块,最后新增的边的权值和等于 (size(u) * size(v)-1) * (w+1),减去1是因为自身已经连同不需要加边。
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define x first
#define y second
typedef pair<int,int> PII;
const int N=6e3+10,M=2e7+10;
int n,m,k,ans,ecnt;
int fa[N],head[N],s[N];
struct edge {
int u,v,next;
double w;
} E[M<<1];
bool cmp(edge a,edge b) {
return a.w<b.w;
}
void add(int u,int v,double w) {
E[++ecnt].u=u;
E[ecnt].v=v;
E[ecnt].w=w;
E[ecnt].next=head[u];
head[u]=ecnt;
}
int findFa(int x) {
return x==fa[x]?x:fa[x]=findFa(fa[x]);
}
//最小生成树
int kruskal() {
sort(E+1,E+1+ecnt,cmp);
int res=0;
for(int i=1; i<=ecnt; i++) {
int x=E[i].u;
int y=E[i].v;
int fx=findFa(x),fy=findFa(y);
if(fx!=fy) {
res+=(s[fx]*s[fy]-1)*(E[i].w+1);//关键
fa[fx]=fy;
s[fy]+=s[fx];
}
}
return res;
}
int main() {
int T;
cin>>T;
while(T--) {
ecnt=0;
memset(head,0,sizeof head);
memset(fa,0,sizeof fa);
memset(s,0,sizeof s);
cin>>n;
for(int i=1; i<=n; i++) {
fa[i]=i;
s[i]=1;
}
for(int i=1; i<=n-1; i++) {
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
cout<<kruskal()<<endl;
}
return 0;
}