树的直径:树上最远两点的距离
求直径方法:
先在任意一点做dfs找到离它最远的一个点作为直径的其中一个端点
再以这个端点再做一次dfs找到另一个端点。
两个端点的距离就是树的直径。
一般可能会需要求出每一个点关于两个端点的距离,那就在每次dfs时注意一下相关数组即可
大意:给定一棵树,要求构造n-1条边,使得每两个点的距离唯一且尽可能大。求边权之和。
思路:找到直径的两个端点,树上离每一个点最远的点一定是两个直径之一,遍历每一个点时取到两个端点的距离的最大值即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+5000;
ll n;
struct ty{
ll l,t,next;
}edge[N*2];
ll cnt=0;
ll head[N*2];
void add(ll a,ll b,ll c){
edge[++cnt].l=c;
edge[cnt].t=b;
edge[cnt].next=head[a];
head[a]=cnt;
}
ll a,b,c;
ll dis1[N];
ll dis2[N];
ll mxp1,mxp2,mxd;
ll ans=0;
void dfs(ll u,ll d,ll p,ll *doo){
doo[u]=d;
for(int i=head[u];i!=-1;i=edge[i].next){
ll y=edge[i].t;
if(y==p) continue;
dfs(y,d+edge[i].l,u,doo);
}
return;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while(cin>>n){
ans=0;
cnt=0;//多组样例清空cnt
memset(head,-1,sizeof head);
memset(dis1,0,sizeof dis1);
memset(dis2,0,sizeof dis2);
for(int i=1;i<n;++i){
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs(1,0,-1,dis1);
mxd=0,mxp1=0;
for(int i=1;i<=n;++i){
if(dis1[i]>mxd){
mxd=dis1[i];
mxp1=i;
}
}
//找到第一个端点
dfs(mxp1,0,-1,dis1);
mxd=0,mxp2=0;
for(int i=1;i<=n;++i){
if(dis1[i]>mxd){
mxd=dis1[i];
mxp2=i;
}
}
//找到第二个端点
dfs(mxp2,0,-1,dis2);//更新dis2数组
ans=0;
for(int i=1;i<=n;++i){
ans+=max(dis1[i],dis2[i]);
}
cout<<ans-dis1[mxp2]<<endl;
}
return 0;
}