【NOIP2012模拟8.10】生成输入数据

这题可以很容易就想到,
由于我们要将最小生成树变成原来的完全图,而且要使边权和最小。
那么:如果我们在x和y连一条边,那么这条边的长度变为↙
那个最小生成树中x到y的路径上最大的边权+1。
这样子暴力O(n2),只能拿50分。
我们考虑优化。(用并查集)
模拟一遍最小生成树,每次合并的时候记录一下每块的个数,并添加答案。
上标:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(x,y) x>y ? x:y
using namespace std;
struct node{int a,b,w;}a[20010];
int T,n,fa[20010],son[20010];
long long ans=0;

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

int cmp(node x,node y) {return x.w<y.w;}

int gf(int x)
{
	if (!fa[x]) return x;
	son[fa[x]]+=son[x],son[x]=0;
	return fa[x]=gf(fa[x]);
}

int main()
{
	freopen("B.in","r",stdin);
//	freopen("B.out","w",stdout);
	T=read();
	while (T--)
	{
		n=read();
		for (int i=1;i<=n;i++) son[i]=1,fa[i]=0;
		for (int i=1;i<n;i++)
			a[i].a=read(),a[i].b=read(),a[i].w=read();
		sort(a+1,a+n,cmp);ans=0;
		for (int i=1,x,y;i<n;i++)
		{
			x=gf(a[i].a),y=gf(a[i].b);
			ans+=((long long)son[x]*son[y])*(a[i].w+1)-1;
			fa[x]=y;son[y]+=son[x],son[x]=0;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2019-01-19 12:46  jz929  阅读(113)  评论(0编辑  收藏  举报