2017湘潭邀请赛 H Highway

题意:给你一个树,每条边都有边权,那么你就知道这可树上任意两点之间的距离,让你用这些距离,重新建一颗树,一颗最大生成树。

解:

在新树中,每个点连边要么和最长的连边要么就和次长的连边。

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define en '\n'
#define ll long long
const ll inf=0x3f3f3f3f;
using namespace std;
const ll maxn =1e5+10;
inline ll read() {
    char c = getchar(); ll x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x ;
}
#define logm 18
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
ll mx[maxn][logm],mi[maxn][logm],fa[maxn];
ll lg[maxn];
ll to[maxn][2];
struct node{
ll v,nxt,w;
}edge[maxn<<1];
ll tot,head[maxn],cnt;
void add(ll x,ll y,ll w){
    ++tot;
    edge[tot].v=y;
    edge[tot].nxt=head[x];
    edge[tot].w=w;
    head[x]=tot;
}
ll dp[maxn][2];
ll from[maxn],n,m;
void dfs_1(ll x,ll f){
    dp[x][0]=dp[x][1]=0;
    to[x][0]=to[x][1]=x;
    for(ll i=head[x];i;i=edge[i].nxt){
        ll y=edge[i].v;if(y==f)continue;
        dfs_1(y,x);
        ll va=edge[i].w;
        if(dp[y][0]+va>dp[x][0]){
            dp[x][1]=dp[x][0],to[x][1]=to[x][0];dp[x][0]=dp[y][0]+va,to[x][0]=to[y][0];
            from[x]=y;
        }
        else if(dp[y][0]+va>dp[x][1]){
            dp[x][1]=dp[y][0]+va,to[x][1]=to[y][0];
        }
    }
}
void dfs_2(ll x,ll f){
    for(ll i=head[x];i;i=edge[i].nxt){
        ll y=edge[i].v;if(y==f)continue;
        if(from[x]!=y){
            if(dp[y][0]<dp[x][0]+edge[i].w){
                dp[y][1]=dp[y][0],to[y][1]=to[y][0];
                dp[y][0]=dp[x][0]+edge[i].w,to[y][0]=to[x][0];
                from[y]=x;
            }
            else if(dp[y][1]<dp[x][0]+edge[i].w){
                dp[y][1]=dp[x][0]+edge[i].w,to[y][1]=to[x][0];
            }
        }
        else{
            if(dp[y][0]<dp[x][1]+edge[i].w){
                dp[y][1]=dp[y][0],to[y][1]=to[y][0];
                dp[y][0]=dp[x][1]+edge[i].w,to[y][0]=to[x][1];
                from[y]=x;
            }
            else if(dp[y][1]<dp[x][1]+edge[i].w){
                dp[y][1]=dp[x][1]+edge[i].w,to[y][1]=to[x][1];
            }
        }
        dfs_2(y,x);
    }
}

ll find(ll x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}




signed main() {
    #ifdef local
    freopen("input2.txt","r",stdin);
    #endif // local
    #define int register int
    #define mem(a,b) memset(a,b,sizeof(a))
    while(scanf("%lld",&n)!=EOF){
        if(n==0 and m==0)break;
        cnt=tot=0;
        mem(head,0);
        for(ll i=1;i<=n;i++)fa[i]=i;
        for(ll i=1;i<n;++i){
            ll x=read(),y=read(),w=read();
            add(x,y,w),add(y,x,w);
        }
    dfs_1(1,0);dfs_2(1,0);
    ll ans=0;
    for(ll i=1;i<=n;i++){
        ll y=to[i][0];
        ll xx=find(i),yy=find(to[i][0]);
        if(xx==yy){
            yy=find(to[i][1]);
            fa[xx]=yy;
            ans+=dp[i][1];
        }
        else{
            fa[xx]=yy;
            ans+=dp[i][0];
        }
    }   cout<<ans<<en;
}
return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值