[BZOJ 1509] 逃学的小孩
Link:
Solution:
一开始受样例影响又犯了想当然的毛病……图中的C点不一定在直径上!
3次$dfs$求出树的直径及直径的两个端点$rt1,rt2$到每个点的距离$d1,d2$,
则结果为$max\{ Diameter+min\{ d1[i],d2[i] \} \}$
Tips:如果要求出直径上每个点或求点到直径端点的距离时,最好还是用2次$dfs$的方法,而不使用一遍$dfs$法
Code:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=2e5+10; struct edge{int to,nxt,w;}e[MAXN<<2]; int n,m,rt1,rt2,head[MAXN],tot=-1; ll d1[MAXN],d2[MAXN],dia=0,res=0; void add_edge(int x,int y,int z) { e[++tot].nxt=head[x];e[tot].to=y;e[tot].w=z;head[x]=tot; e[++tot].nxt=head[y];e[tot].to=x;e[tot].w=z;head[y]=tot; } void dfs(int x,int anc) { for(int i=head[x];i!=-1;i=e[i].nxt) { if(e[i].to==anc) continue; d1[e[i].to]=max(d1[e[i].to],d1[x]+e[i].w); dfs(e[i].to,x); } } int main() { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head));d1[0]=-1e15; for(int i=1;i<=m;i++) { int x,y,z;scanf("%d%d%d",&x,&y,&z); add_edge(x,y,z); } dfs(1,0);for(int i=1;i<=n;i++) if(d1[i]>d1[rt1]) rt1=i; memset(d1,0,sizeof(d1));d1[0]=-1e15;dfs(rt1,0); for(int i=1;i<=n;i++) { if(d1[i]>d1[rt2]) rt2=i; d2[i]=d1[i];dia=max(dia,d1[i]); } memset(d1,0,sizeof(d1));dfs(rt2,0); for(int i=1;i<=n;i++) res=max(res,dia+min(d1[i],d2[i])); printf("%lld",res); return 0; }