Description
首先看到题目别太开心,这题可不是让你出数据~^_*
背景神马的就忽略了。这题就是给你一棵带边权的树,然后这棵树是某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。
完全图是任意两个点之间都有边相连的图。
Input
第一行包含一个整数T表示数据组数。
每组数据第一行一个整数N表示点数。
接下来N-1行每行三个整数ai,bi,wi表示最小生成树上ai和bi之间有一条权值为wi的边。
Output
输出应有T行,每行表示一组数据的答案。
Sample Input
2 3 1 2 4 2 3 7 4 1 2 1 1 3 1 1 4 2
Sample Output
19 12
Data Constraint
Hint
20%的数据满足:T≤5,n≤5,wi≤5
另外30%的数据满足:n≤1000,给定的树是一条链
100%的数据满足:T≤10,n≤20000,wi≤10000
By moreD
分析
题目和题面无关系列
考场的时候不知道为什么总觉得可以有奇怪的方法,打了一波计算用set维护然后20分WA
事实上只用模仿生成最小生成树的过程即可
我们合并两棵树时,我们可以确定其中必定只有一条边是最小生成树内的,需要添加的边数=两棵树大小的乘积-1,边的权值为最小生成树树边的权值+1
然后再加上原树总值就算出来了
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=2e4+10; struct Edge { int u,v,w; }g[N]; int f[N],sz[N]; int T,n; int Get_F(int x) {return f[x]==x?x:f[x]=Get_F(f[x]);} bool CMP(Edge a,Edge b) { return a.w<b.w; } int main() { for (scanf("%d",&T);T;T--) { scanf("%d",&n); for (int i=1;i<n;i++) scanf("%d%d%d",&g[i].u,&g[i].v,&g[i].w),sz[i]=1,f[i]=i; f[n]=n;sz[n]=1;long long ans=0; sort(g+1,g+n,CMP); for (int i=1;i<n;i++) { int fu=Get_F(g[i].u),fv=Get_F(g[i].v); if (fu!=fv) { ans+=1ll*(sz[fu]*sz[fv]-1ll)*(g[i].w+1ll); sz[fu]+=sz[fv]; f[fv]=fu; ans+=g[i].w; } } printf("%lld\n",ans); } }