树网的核
一个线性时间复杂度的做法
找一条直径(两遍dfs),然后从一个端点开始枚举长度不超过s的另一端点(由贪心的性质显然当长度刚好小于s时比较优 )
然后偏心距的下界大于这个端点到直径两端点的最小值
然后对于一条路径的偏心距我们发现如果去一个点要经过你的路径,这个距离显然是没有用的(因为从路径上到这个点一定有更小的距离)
所以我们就将他们无视掉
#include<bits/stdc++.h> using namespace std; #define maxn 500005 inline int read() { char ch='*'; int num=0,f=1; while(!isdigit(ch)){ ch=getchar(); if(ch == '-' ) f = -1; } while(isdigit(ch)) { num = num * 10 +ch -'0'; ch = getchar(); } return num*f; } //struct edge {int to,val}; vector<pair<int ,int > > e[maxn]; int dis[maxn]; bool vis[maxn]; int fa[maxn]; int n,m,s; void dfs(int x) { int siz=e[x].size(); siz--; for(int i=0;i<=siz;i++) { int v=e[x][i].first; if(vis[v]||fa[x]==v) continue ; fa[v]=x; dis[v]=dis[x]+e[x][i].second; dfs(v); } return; } int main() { n=read(); s=read(); int u,v,w; for(int i=1;i<n;i++) { u=read();v=read();w=read(); e[u].push_back(make_pair(v,w)); e[v].push_back(make_pair(u,w)); } int l=1,l2=1; dis[l]=0; dfs(l); memset(fa,0,sizeof(fa)); for(int i=1;i<=n;i++) if(dis[i]>dis[l]) l=i; dis[l]=0; dfs(l); for(int i=1;i<=n;i++) if(dis[i]>dis[l2] ) l2=i; int ans=0x7fffffff,j=l2; for(int i=l2;i;i=fa[i]){ while(fa[j]&&dis[i]-dis[fa[j]]<=s) j=fa[j]; ans=min(ans,max(dis[j],dis[l2]-dis[i])); } for(int i=l2;i;i=fa[i]) vis[i]=1; for(int i=l2;i;i=fa[i]) dis[i]=0,dfs(i); for(int i=1;i<=n;i++) ans=max(ans,dis[i]); cout<<ans<<endl; return 0; }