题目地址


易错点:

  • 求树的直径的端点时,在获取最深的点时应当使用">="符号.
  • 求树的直径时需要附带vis[i]数组以保证每个点仅访问一次(源点dis为0).

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN=3e5,MAXM=MAXN*2;
struct Edge{
	int from,to,nxt;
	ll w;
}e[MAXM];
int head[MAXN],edgeCnt=1;
void addEdge(int u,int v,ll w){
	e[++edgeCnt].from=u;
	e[edgeCnt].to=v;
	e[edgeCnt].w=w;
	e[edgeCnt].nxt=head[u];
	head[u]=edgeCnt;
}
ll dep[MAXN];
bool vis[MAXN];
int n;
ll length;//树的直径 
int bfs(int s){//返回深度最大的点 
	memset(dep,0,sizeof(dep));
	memset(vis,0,sizeof(vis));
	queue<int> q;
	q.push(s);
	vis[s]=1;
	while(!q.empty()){
		int nowU=q.front();
		q.pop();
		for(int i=head[nowU];i;i=e[i].nxt){
			int nowV=e[i].to;
			if(!vis[nowV]){
				dep[nowV]=dep[nowU]+e[i].w;
				vis[nowV]=1;
				q.push(nowV);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		if(dep[ans]<=dep[i]){//注意( "=" )
			ans=i;
			length=dep[i];
		}
	return ans;
}
ll dis1[MAXN];
void dfs1(int x,int in_edge){
	for(int i=head[x];i;i=e[i].nxt){
		if(i==(in_edge^1))continue;
		int nowV=e[i].to;
		dis1[nowV]=dis1[x]+e[i].w;
		dfs1(nowV,i);
	}
}
ll dis2[MAXN];
void dfs2(int x,int in_edge){
	for(int i=head[x];i;i=e[i].nxt){
		if(i==(in_edge^1))continue;
		int nowV=e[i].to;
		dis2[nowV]=dis2[x]+e[i].w;
		dfs2(nowV,i);
	}	
}
int main(){
	int m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int u,v;
		ll w;
		cin>>u>>v>>w;
		addEdge(u,v,w);
		addEdge(v,u,w);
	}
	int st=bfs(1);
	int ed=bfs(st);//树上直径的两端点 
	dfs1(st,0);
	dfs2(ed,0);
	ll ans=0;
	for(int i=1;i<=n;i++)
		ans=max(ans,min(dis1[i],dis2[i]));//最坏情况下
	ans=ans+length;
	cout<<ans<<endl;
	return 0;
}