版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34283998/article/details/82961774
想到了按边算贡献,然而却偏向了在直径上鬼畜的道路.
通过观察,可以发现如果多次经过重心,答案应该是最优的.因为这样使得除了某一条特殊的边之外,所有的边都会被计算两次.而这条特殊的边有两种情况,首先是只有一个重心,那么我们选择边权最小的且其中一个端点为重心的边;另一种情况是具有两个重心,选择两个重心之间的边即可.
此处复习一下求重心的方法,首先任选一个节点为根,统计出每一个节点对应子树的大小,最大儿子的大小.然后可以求出以这个点为根最大的子树大小,当一个节点的最大子树小于等于节点数的一半时,那么这个点就是重心.
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
const ll INF=1e18;
int n,p1,p2;
ll ans,ex=INF;
int siz[MAXN],mx[MAXN];
vector<pair<int,int> > E[MAXN];
void dfs1(int u,int fa=0){
siz[u]=1;
for(int i=0;i<(int)E[u].size();i++){
int v=E[u][i].first;
if(v==fa) continue;
dfs1(v,u);
siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
mx[u]=max(mx[u],n-siz[u]);
if(mx[u]<=n/2){
if(!p1) p1=u;
else p2=u;
}
}
void dfs2(int u,int fa=0,ll sum=0){
ans+=2*sum;
for(int i=0;i<(int)E[u].size();i++){
int v=E[u][i].first,val=E[u][i].second;
if(v==fa) continue;
dfs2(v,u,sum+val);
if(v==p2||(!p2&&u==p1)) ex=min(ex,1ll*val);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v,val;
scanf("%d%d%d",&u,&v,&val);
E[u].push_back(make_pair(v,val));
E[v].push_back(make_pair(u,val));
}
dfs1(1);
dfs2(p1);
printf("%lld",ans-ex);
}