#点分治,Kruskal#AT3611 Tree MST

题目

给定一棵 \(n\) 个节点的树,现有有一张完全图,

两点 \(x,y\) 之间的边长为 \(w_x+w_y+dis_{x,y}\)

其中 \(dis\) 表示树上两点的距离。

求完全图的最小生成树。


分析

考虑两两点对都会在重心的位置被统计一次,

而可以在此过程连边,只要找到当前子树\(\min\{w_x+d_x\}\)所对应的\(x\)

一共\(O(n\log_2 n)\)条边,直接跑Kruskal即可


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=200011;
struct node{int y,w,next;}e[N<<1];
struct rec{int x,y; long long w;}b[N<<5];
long long ans,d[N]; bool v[N];
int big[N],siz[N],a[N],SIZ,f[N],cho;
int root,n,m,as[N],tot,et=1,B[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
bool cmp(rec x,rec y){return x.w<y.w;}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline signed max(int a,int b){return a>b?a:b;}
inline void dfs(int x,int fa){
	siz[x]=1,big[x]=0;
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fa&&!v[e[i].y]){
		dfs(e[i].y,x);
		siz[x]+=siz[e[i].y];
		big[x]=max(big[x],siz[e[i].y]);
	}
	big[x]=max(big[x],SIZ-siz[x]);
	if (big[x]<=big[root]) root=x;
}
inline void calc(int x,int fa){
	B[++tot]=x;
    if (a[cho]+d[cho]>a[x]+d[x]) cho=x;
	for (rr int i=as[x];i;i=e[i].next)
	if (!v[e[i].y]&&e[i].y!=fa)
		d[e[i].y]=d[x]+e[i].w,calc(e[i].y,x);
}
inline void dp(int x){
	v[x]=1,d[x]=0,cho=B[tot=1]=x;
	for (rr int i=as[x];i;i=e[i].next)
	    if (!v[e[i].y]) d[e[i].y]=d[x]+e[i].w,calc(e[i].y,x);
	for (rr int i=1;i<=tot;++i)
		b[++m]=(rec){cho,B[i],a[cho]+d[cho]+a[B[i]]+d[B[i]]};
	for (rr int i=as[x];i;i=e[i].next)
	if (!v[e[i].y]){
		big[0]=SIZ=siz[e[i].y];
		dfs(e[i].y,root=0),dp(root);
	}
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut(),f[i]=i;
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut(),w=iut();
		e[++et]=(node){y,w,as[x]},as[x]=et;
		e[++et]=(node){x,w,as[y]},as[y]=et;
	}
	big[0]=SIZ=n,dfs(1,root=0),dfs(root,0),dp(root);
	sort(b+1,b+1+m,cmp);
	for (rr int i=1;i<=m;++i){
		rr int fa=getf(b[i].x),fb=getf(b[i].y);
		if (fa!=fb) f[fa]=fb,ans+=b[i].w;
	}
	return !printf("%lld",ans);
}
posted @ 2021-08-24 11:38  lemondinosaur  阅读(29)  评论(0编辑  收藏  举报