官方题解在这
首先注意到任意两条边的边权是不一样的,由此得知最小生成树是唯一的,最小生成树既然 是唯一的,那么期望其实也就是唯一的,不存在什么最小期望。求完最小生成树之后,接下 来的问题就可以转换成在最小生成树上求任意两点之间距离的平均值,对于每条边,统计所 有的路径用到此边的次数,也就是边的两端的点数之积。那么这条边的总贡献就是次数边 权。最后得到所有边的贡献之和再除以总路径数n∗(n−1)/2n(n-1)/2n∗(n−1)/2就是答案。可以OnOnOn求出。任取一点为根dfs,对每个点iii记录其子树包含的点数(包括其自身),设点数为sum[i]sum[i]sum[i],则iii的父亲一侧的点数即为n−sum[i]n-sum[i]n−sum[i]。一边遍历一边统计就行。
懒,longlong是个巨坑点,,,比赛时交了27次还没过(好菜啊)
今天改个I64d就过了,,,心累
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int M=1000007;
const int N=100007;
int m;
ll n;
struct Edge{
int x,y;
ll w;
Edge(){}
Edge(int a,int b,ll c){x=a;y=b;w=c;}
bool operator < (const Edge e)const{return w<e.w;}
}edges[M];
vector<int>g[N];
void Link(int x,int y,int e){
g[x].push_back(e);
g[y].push_back(e);
}
int f[N];
int F(int x){
return x==f[x]?x:(f[x]=F(f[x]));
}
int a[N];
bool vis[N];
ll SUM;
void DFS(int x){
vis[x]=1;
a[x]+=1;
for (int i=0;i<g[x].size();i++){
Edge e=edges[g[x][i]];
int y;if (e.x==x)y=e.y;else y=e.x;
if (vis[y])continue;
DFS(y);
SUM=SUM+(ll)((ll)(n-a[y])*(ll)(a[y])*e.w);
a[x]+=a[y];
}
}
int main(){
//freopen("fuck.in","r",stdin);
int T,x,y;
ll z;
scanf("%d",&T);
while (T--){
scanf("%I64d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d%d%I64d",&x,&y,&z);
edges[i]=Edge(x,y,z);
}
for (int i=1;i<=n;i++)g[i].clear();
sort(edges+1,edges+m+1); //kruskal
for (int i=1;i<=n;i++)f[i]=i;
int cnt=0;
ll sum=0;
for (int i=1;i<=m;i++){
int x=edges[i].x;
int y=edges[i].y;
if (F(x)==F(y))continue;
f[f[x]]=F(y);
cnt++;
Link(x,y,i);
sum=sum+edges[i].w;
if (cnt==n-1)break;
}
SUM = 0;
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
DFS(1);
double ans=2.0*SUM/(n*(n-1));
printf("%I64d %.2lf
",sum,ans);
}
return 0;
}