jzoj2940. 生成输入数据 (Standard IO)
题目大意:
给你一棵带边权的树,然后这棵树是某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。
(完全图是任意两个点之间都有边相连的图。)
题解
考虑最小生成树的定义,若我们先按照树边边权从小到大排序,一条边两端的联通块中任意一组点对(除与这条树边直接相连的两点)对答案的贡献都是该树边边权加一。为什么?因为该边是两联通块中任一点对的路径上最小值,而题目中强调“唯一的最小生成树”,故上结论成立。
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e4 + 100;
inline void read(int &x)
{
x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0' , c = getchar();
}
struct note
{
int u , v , val;
bool operator <(const note &a)
const
{
return val < a.val;
}
inline void getin(){read(u) , read(v) ,read(val);}
}g[N];
int t , n , size[N] , fa[N];
inline int getfa(int x){return x == fa[x] ? fa[x] : getfa(fa[x]);}
int main()
{
for(read(t) ; t ; t --)
{
read(n);long long ans = 0;
for(int i = 1;i < n;i ++) g[i].getin();
for(int i = 1;i <= n;i ++) fa[i] = i , size[i] = 1;
sort(g + 1 , g + n);
for(int i = 1;i < n;i ++)
{
int x = getfa(g[i].u) , y = getfa(g[i].v);
if(size[x] < size[y]) x ^= y ^= x ^= y;
ans += 1ll * (g[i].val + 1) * size[x] * size[y] - 1, size[x] += size[y] , fa[y] = x;
}
printf("%lld\n",ans);
}
return 0;
}