【JZOJ2940】生成输入数据

探讨在一棵作为某完全图唯一最小生成树的带边权树中,如何计算原完全图所有边可能的最小边权总和。通过分析树上不相邻节点间的边权关系,采用并查集算法进行边的加入与权重计算,最终得出最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

description

首先看到题目别太开心,这题可不是让你出数据~^_*

背景神马的就忽略了。这题就是给你一棵带边权的树,然后这棵树是某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。

完全图是任意两个点之间都有边相连的图。


analysis

  • 对于前505050分可以分别用暴力和线段树拿到

  • 其实一条链的情况就在提示正解了

  • 思考一下,对于MSTMSTMST树上不相邻的两个点,既然它们被选出来,意味着什么

  • 其实就是说它们在原图之间原有的边一定大于MSTMSTMST树上两点之间路径的最大边

  • 那么对于n−1n-1n1条边,按照权值升序排序,然后一条条加入并查集

  • 对于一条边即将连起来的两个联通块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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值