AT2673 [AGC018D] Tree and Hamilton Path

【题意】

给一个树,求一个哈密顿路径,使得距离最大

【分析】

考虑之前的一道求点对最大和的题目

采取之前的思路,考虑每个边(u,v)的贡献都是min(size[v],n-size[v])那么我们只需要在之前的路径上减去一条边即可

这个边尽可能小,但是要保证在我们构造的解的路径上

这里我们需要观察到这样一个性质,路径一定经过重心,只有这样才能保证最优

那么我们可以通过减去和重心相连的最短边得到最优答案,如果有两个重心删去它们之间的边即可

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int head[maxn],tot;
struct edge
{
    int to,nxt;
    ll v;
}e[maxn<<1];
void add(int x,int y,ll z)
{
    e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; head[x]=tot;
}
int n;
ll ans,siz[maxn],mx[maxn];
void dfs(int u,int fa)
{
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
        siz[u]+=siz[to];
        ans+=2*min(siz[to],n-siz[to])*e[i].v;
        mx[u]=max(mx[u],siz[to]);
    }
    mx[u]=max(mx[u],n-siz[u]);
}
int g1,g2;
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    int T;
    scanf("%d",&n);
    int x,y; ll z;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%lld",&x,&y,&z);
        add(x,y,z); add(y,x,z);
    }
    dfs(1,0);
    ll gsize=1e17;
    for(int i=1;i<=n;i++) gsize=min(gsize,mx[i]);
    for(int i=1;i<=n;i++)
    {
        if(mx[i]!=gsize) continue;
        if(!g1) g1=i;
        else g2=i;
    }
    ll delta=1e17;
    for(int i=head[g1];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(g2 && to!=g2) continue;
        delta=min(delta,e[i].v);
    }
    printf("%lld",ans-delta);
    return 0;
}

 

posted @ 2021-10-17 21:39  andyc_03  阅读(22)  评论(0编辑  收藏  举报