1. 程式人生 > >AtCoder Grand Contest 018 D - Tree and Hamilton Path

AtCoder Grand Contest 018 D - Tree and Hamilton Path

題目傳送門:https://agc018.contest.atcoder.jp/tasks/agc018_d

題目大意:

給定一棵\(N\)個點的帶權樹,求最長哈密頓路徑(不重不漏經過每個點一次,兩點之間轉移可以看做瞬移,對答案貢獻為兩點之間的距離)

這道題直接計算不好算,我們考慮每條邊的貢獻,基於一種貪心的思想,我們發現只要圍著樹的重心跑,就可以使每條邊得到充分利用

考慮邊i的貢獻,我們假定邊i割掉後分成兩個大小為x,y的聯通塊,那麼貢獻則為\(2*v[i]*min(x,y)\)

因為我們走的不是迴路,因此有一條邊不會被算兩次。如果樹的重心只有一個,那麼必然減去與重心相連的邊權最小的邊;如果樹的重心有兩個,減去兩重心相連的邊即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1;char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=2e5;
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],val[(N<<1)+10];
int size[N+10],Msize[N+10];
int n,tot,rize,root;
ll Ans;
void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
void dfs(int x,int fa,int v){
    int Max=0; size[x]=1;
    for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
        if (son==fa)    continue;
        dfs(son,x,val[p]),size[x]+=size[son];
        Max=max(Max,size[son]);
    }
    Ans+=1ll*min(size[x],n-size[x])*v*2;
    Max=max(Max,n-size[x]);
    Msize[x]=Max;
    if (Max<rize){
        rize=Max;
        root=x;
    }
}
int main(){
    n=read(),rize=inf;
    for (int i=1;i<n;i++){
        int x=read(),y=read(),z=read();
        insert(x,y,z);
    }
    dfs(1,0,0);
    int tmp=inf;
    for (int p=now[root],son=child[p];p;p=pre[p],son=child[p]){
        tmp=min(tmp,val[p]);
        if (Msize[root]==Msize[son]){
            Ans-=val[p];
            printf("%lld\n",Ans);
            return 0;
        }
    }
    printf("%lld\n",Ans-tmp);
    return 0;
}