description
首先看到题目别太开心,这题可不是让你出数据~^_*
背景神马的就忽略了。这题就是给你一棵带边权的树,然后这棵树是某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。
完全图是任意两个点之间都有边相连的图。
analysis
-
对于前505050分可以分别用暴力和线段树拿到
-
其实一条链的情况就在提示正解了
-
思考一下,对于MSTMSTMST树上不相邻的两个点,既然它们被选出来,意味着什么
-
其实就是说它们在原图之间原有的边一定大于MSTMSTMST树上两点之间路径的最大边
-
那么对于n−1n-1n−1条边,按照权值升序排序,然后一条条加入并查集
-
对于一条边即将连起来的两个联通块x,yx,yx,y,这条边一定比联通块里的所有边要大且至少比最大值大111
-
所以就会产生size[x]∗size[y]∗(边权+1)−1size[x]*size[y]*(边权+1)-1size[x]∗size[y]∗(边权+1)−1的贡献,并每次并查集合并两个联通块就好了
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 20005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll fa[MAXN],size[MAXN];
ll n,T,ans;
struct node
{
ll x,y,z;
}a[MAXN];
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline bool cmp(node a,node b)
{
return a.z<b.z;
}
O3 inline ll getfa(ll x)
{
return !fa[x]?x:fa[x]=getfa(fa[x]);
}
O3 int main()
{
//freopen("T2.in","r",stdin);
T=read();
while (T--)
{
memset(fa,0,sizeof(fa));
size[n=read()]=1,ans=0;
fo(i,1,n-1)a[i].x=read(),a[i].y=read(),a[i].z=read(),size[i]=1;
sort(a+1,a+n,cmp);
fo(i,1,n-1)
{
ll x=getfa(a[i].x),y=getfa(a[i].y);
ans+=size[x]*size[y]*(a[i].z+1)-1;
fa[x]=y,size[y]+=size[x];
}
printf("%lld\n",ans);
}
return 0;
}