U81904 【模板】树的直径
题目描述
给定一棵树,树中每条边都有一个权值,
树中两点之间的距离定义为连接两点的路径边权之和。
树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。
现在让你求出树的最长链的距离
输入格式
给定一棵无根树
第一行为一个正整数nnn,表示这颗树有nnn个节点
接下来的n−1n-1n−1行,每行三个正整数u,v,wu,v,wu,v,w,表示u,vu,vu,v(u,v<=nu,v<=nu,v<=n)有一条权值为www的边相连
数据保证没有重边或自环
输出格式
输入仅一行,表示树的最长链的距离
输入输出样例 #1
输入 #1
6
1 2 1
1 3 2
2 4 3
4 5 1
3 6 2
输出 #1
9
说明/提示
对于1010%10的数据 n<=10n<=10n<=10
对于3030%30的数据 n<=1000n<=1000n<=1000
对于5050%50的数据 n<=10000n<=10000n<=10000
对于7070%70的数据 n<=100000n<=100000n<=100000 边权均为正整数
对于100100%100的数据 n<=500000n<=500000n<=500000 边权可能为负
题解
两遍dfs版本(90分),适用于边权非负的树
优点:可以获取的信息多,能获得直径沿途的边
缺点:需要遍历两次
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
typedef long long ll;
int n,st,ed,dis;
vector<pair<int,int>>e[N];
int dist[N],last[N];
void dfs(int u,int f,int w)
{last[u]=f;dist[u] = dist[f]+w;for(auto x:e[u]){int v = x.first;int ww = x.second;if(v==f)continue;dfs(v,u,ww);}
}void road()
{dfs(1,0,0);st = 1;for(int i=2;i<=n;i++){if(dist[st]<dist[i]){st = i;}}dfs(st,0,0);ed=1;for(int i=2;i<=n;i++){if(dist[ed]<dist[i]){ed = i;}}dis = dist[ed];
}void solve()
{cin>>n;for(int i=1;i<n;i++){int u,v,w;cin>>u>>v>>w;e[u].push_back({v,w});e[v].push_back({u,w});}road();cout<<dis<<endl;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;// cin>>t;while(t--){solve();}return 0;
}
树型dp(100分),适用于任何树
优点:只需要遍历一次
缺点:只能求直径
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
typedef long long ll;
int n,st,ed,dis;
vector<pair<int,int>>e[N];
int dist[N],ans[N];void dp(int u,int f)
{for(auto x:e[u]){int v = x.first;if(v==f)continue;dp(v,u);}for(auto x:e[u]){int v = x.first;int w = x.second;if(v==f)continue;ans[u]=max(ans[u],dist[u]+dist[v]+w);dist[u]=max(dist[u],dist[v]+w);}
}void solve()
{cin>>n;for(int i=1;i<n;i++){int u,v,w;cin>>u>>v>>w;e[u].push_back({v,w});e[v].push_back({u,w});}dp(1,0);dis = INT_MIN;for(int i=1;i<=n;i++){dis = max(dis,ans[i]);}cout<<dis<<endl;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;// cin>>t;while(t--){solve();}return 0;
}
