A Abandoned country
最小生成树 + 树上任意点对距离之和
树上任意点对距离之和:
计算时考虑每一个边,它的贡献值为它的 左端点以左的点的个数 * 右端点以右的点的个数 * 该边的权值。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int,ll> PIL;
const int N =1e5+10;
const int NN = 1e6+10;
int father[N];
int n,m,cntt;
int vis[N];
ll tot;
double di;
struct Edge
{
int a, b;
ll v;
bool operator< (const Edge &W) const
{
return v < W.v;
}
}edge[NN];
vector< pair<int,ll> >tedges[N];
int find(int x)
{
if (father[x] != x) father[x] = find(father[x]);
return father[x];
}
ll Kruskal()
{
ll res =0;
for (int i = 1; i <= n; i ++ ) father[i] = i;
sort(edge, edge + m);
for (int i = 0; i < m; i ++ )
{
int a = edge[i].a, b = edge[i].b;
ll v =edge[i].v;
if (find(a) != find(b))
{
tedges[a].push_back({b,v});
tedges[b].push_back({a,v});
res += v;
father[find(a)] = find(b);
}
}
return res;
}
ll dfs(int cur)
{
vis[cur]=1;
ll now = 0 ,ans = 1;
for(int i=0;i<tedges[cur].size();i++)
{
if(!vis[tedges[cur][i].first])
{
now = dfs(tedges[cur][i].first);
ans += now;
tot += tedges[cur][i].second * (n-now) * now; //tot保存边的贡献和
//下方的点数可由dfs求得,其余的点为(n-下方的点)
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
tot=0;
cntt = 0;
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)tedges[i].clear();
//tedges[0] = {1,0};
di = (double)n*(n-1)/2;
for(int i=0;i<m;i++)
{
scanf("%d%d%lld",&edge[i].a,&edge[i].b,&edge[i].v);
}
ll ans = Kruskal();
dfs(1);
printf("%lld %.2f\n",ans,(double)tot/di);
}
return 0;
}