Tree and Hamilton Path
Problem Statement
给出一棵有
n
个点的带边权的树,边权≤
Data Constraint
n
<=
Solution
一个显然的结论,一条边(
a
,
先找出树的重心,接下来分类讨论。
若只有一个重心,也就意味着重心的每棵子树的大小严格小于
n2
,那么设
p1
为重心,上限就一 定可以跑满(若干棵子树间跳来跳去,每次从一棵中跳到另一棵),但我们可以发现,唯独重心连向各棵子树的边中的其中一条边会比上限少
1
(因为
若有两个重心,则这两个重心一定连在一起,并且若把连接它们的边断开可以分成两棵大小严格为 n2 的树。接着我们可以发现,连着两个重心的边最多只能跑上限- 1 <script type="math/tex" id="MathJax-Element-464">1</script>次,而其他边都能跑满上限,统计答案即可。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=12e4,M=2*N;
int fa[N],ne[M],la[N],lb[M],size[N],zd[N];
ll len[M],ans=0;
int oo,n;
ll ok=0;
inline void llb(int a,int b,ll z)
{ne[++oo]=la[a]; la[a]=oo; lb[oo]=b; len[oo]=z;};
inline int min(int a,int b)
{return a<b?a:b;}
inline int max(int a,int b)
{return a>b?a:b;}
inline ll min(ll a,ll b)
{return a<b?a:b;}
inline ll readll()
{
ll o=0; char ch=' ';
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
return o;
}
inline int read()
{
int o=0; char ch=' ';
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
return o;
}
void dg(int o)
{
size[o]=1;
for(int y=la[o];y;y=ne[y])
if(!fa[lb[y]]){
fa[lb[y]]=o;
dg(lb[y]);
size[o]+=size[lb[y]];
if(size[lb[y]]*2==n)ok=len[y];
ans=ans+len[y]*min(size[lb[y]],n-size[lb[y]]);
}
zd[o]=n-size[o];
for(int y=la[o];y;y=ne[y])
if(fa[lb[y]]==o)zd[o]=max(zd[o],size[lb[y]]);
}
int main()
{
cin>>n;
fo(i,1,n-1){
int a=read(),b=read();
ll Z=readll();
llb(a,b,Z); llb(b,a,Z);
}
fa[1]=-1; dg(1);
if(ok==0){
int o=0; zd[0]=n+1;
fo(i,1,n)if(zd[i]<zd[o])o=i;
ok=(ll)12e17;
for(int y=la[o];y;y=ne[y])
ok=min(ok,len[y]);
}
ans=(ans<<1)-ok;
cout<<ans;
}