zoukankan      html  css  js  c++  java
  • #点分治,Kruskal#AT3611 Tree MST

    题目

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

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

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

    求完全图的最小生成树。


    分析

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

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

    一共(O(nlog_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);
    }
    
  • 相关阅读:
    启用数据库 aspnetstate 会话状态
    窗体设计器
    玩转hyper-v
    PDF,IMAGE,HTML,WORD,EXCEL 互操作
    在线浏览office 文件
    使用c#操作txt
    C#里调用 MysqlDB
    c#控件攻略宝典之ListBox控件
    c# word文档与二进制数据的相互转换
    C#对话框的使用
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15179630.html
Copyright © 2011-2022 走看看