牛客练习赛69 C 旅行

H y p e r l i n k Hyperlink Hyperlink

https://ac.nowcoder.com/acm/contest/7329/A


D e s c r i p t i o n Description Description

给定一棵大小为 n n n,边数为 m m m的无向图
定义 d i s t ( u , v ) dist(u,v) dist(u,v)表示从 u u u走到 v v v路经的最小边权的最大值,试给每个点编号使得最终
∑ i = 2 n d i s t ( a i , a i − 1 ) \sum_{i=2}^n dist(a_i,a_{i-1}) i=2ndist(ai,ai1)最大

数据范围: n , m ≤ 5 × 1 0 5 n,m\leq 5\times 10^5 n,m5×105


S o l u t i o n Solution Solution

最终的 d i s t dist dist一定是若干条边,容易证明这些边一定是最大生成树上的边

那么如果边从大到小加入又保证联通的话,这样确定点的编号一定是最优的(读者可自行画图证明,一定要多思考,不然考试考到还是不会做)

用库鲁斯卡尔做法即可

时间复杂度: O ( m l o g m ) O(mlogm) O(mlogm)


C o d e Code Code

#include
#include
#include
#include
#define N 500010
#define LL long long
using namespace std;int n,m,l[N],tot,f[N];
LL ans;
struct node{
     int from,to;LL w;}e[N];
inline bool cmp(node x,node y){
     return x.w>y.w;}
inline int find(int x){
     return x==f[x]?x:f[x]=find(f[x]);}
inline LL read()
{
     
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
signed main()
{
     
	n=read();m=read();
	for(register int i=1;i<=n;i++) f[i]=i;
	for(register int i=1;i<=m;i++) e[i].from=read(),e[i].to=read(),e[i].w=read();
	sort(e+1,e+1+m,cmp);
	for(register int i=1,j=0;i<=m&&j<(n-1);i++)
	{
     
		int fx=find(e[i].from),fy=find(e[i].to);
		if(fx==fy) continue;
		f[fx]=fy;
		j++;
		ans+=e[i].w;
	}
	printf("%lld",ans);
}

你可能感兴趣的:(牛客练习赛69,C,旅行)