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; }