[agc018d]Tree and Hamilton Path

来源:互联网 发布:ubuntu16.04启动mysql 编辑:程序博客网 时间:2024/06/07 01:09

前言

做过类似的idea题。

题目大意

给你一棵树,然后你需要找到一个n的排列[,使得
n1i=1dis(pi,pi+1)
最大,输出答案即可。

做法

假设p1=s,pn=t。
我们提取重心作为根。
设sum为深度和。
答案为2sumdep[s]dep[t]n1i=1dep[lca(pi,pi+1)]
如果原树只有一个重心,显然可以以根为s,然后以任意点为t,中间存在方法使得两两lca均为根。
如果有两个,显然只能以根为s,另一个重心为t,中间也存在方法使两两lca为根。
讲的很菜。。。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=100000+10;const ll inf=100000000000000000;int h[maxn],go[maxn*2],nxt[maxn*2],dis[maxn*2],size[maxn];ll dep[maxn];ll ans,sum,mi,se;bool czy;int i,j,k,l,r,t,n,m,tot,root;void add(int x,int y,int z){    go[++tot]=y;    dis[tot]=z;    nxt[tot]=h[x];    h[x]=tot;}void dfs(int x,int y){    int t=h[x];    while (t){        if (go[t]!=y){            dfs(go[t],x);            size[x]+=size[go[t]];        }        t=nxt[t];    }    size[x]++;}void dg(int x,int y){    int t=h[x];    while (t){        if (go[t]!=y){            dep[go[t]]=dep[x]+(ll)dis[t];            dg(go[t],x);        }        t=nxt[t];    }}int main(){    scanf("%d",&n);    fo(i,1,n-1){        scanf("%d%d%d",&j,&k,&l);        add(j,k,l);add(k,j,l);    }    dfs(1,0);    root=1;t=0;    while (1){        r=h[root];        while (r){            if (go[r]!=t&&size[go[r]]==n/2&&n%2==0){                czy=1;                mi=dis[r];            }            if (go[r]!=t&&size[go[r]]>n/2){                t=root;                root=go[r];                break;            }            r=nxt[r];        }        if (!r) break;    }    dg(root,0);    fo(i,1,n) sum+=dep[i];    if (!czy){        mi=inf;        fo(i,1,n)            if (i!=root) mi=min(mi,dep[i]);    }    ans=sum*2;    ans-=mi;    printf("%lld\n",ans);}