1. 程式人生 > 其它 >AT2673 [AGC018D] Tree and Hamilton Path

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