输入样例#1:
5 2 1 2 5 2 3 2 2 4 4 2 5 3
输出样例#1:
5
输入样例#2:
8 6 1 3 2 2 3 2 3 4 6 4 5 3 4 6 4 4 7 2 7 8 3
输出样例#2:
5
n<=500000
分析
为了方便,st,ed表示直径两端的两个点
首先来看树的核是一个点的情况
证明: 使偏心距最大的点一定是st或ed
若x的偏心距最大,那么直径应该就是x--ed了
同理,当核是一条路径时,x上头和y下头的所有点都是不行的,所以这种情况的偏心距应该为
Max(x到st的距离,y到ed的距离,(x,y)之间任意一个节点到以该节点为根的最远距离
因此我们先dfs出st,然后再dfs出到dis的距离已经ed
然后一个一个往上找s个长度(x,y) 然后更新答案,最后再dfs出直径上的点到自己子树的最大距离然后更新答案
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int first[N],next[N*2],to[N*2],w[N*2],tot;
int n,s,st,ed,ans=0x3fffffff,vis[N];
int dep[N],fa[N],dis[N],dis_st[N],fa_st[N];
int read(){
int cnt=0;char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
void add(int x,int y,int z){
next[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
}
void dfs(int u){
vis[u]=1;
for(int i=first[u];i;i=next[i]){
int t=to[i]; if(vis[t]) continue;
dis[t]=dis[u]+w[i],fa[t]=u,dep[t]=dep[u]+1;
if(dis[t]>dis[st]) st=t;
dfs(t);
}
}
void dfs_st(int u,int f){
for(int i=first[u];i;i=next[i]){
int t=to[i]; if(t==f)continue;
dis_st[t]=dis_st[u]+w[i];
fa_st[t]=u;
if(dis_st[t]>dis_st[ed]) ed=t;
dfs_st(t,u);
}
}
int main(){
freopen("1.in","r",stdin);
n=read(),s=read();
for(int i=1;i<n;i++){
int x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
dep[1]=1,dfs(1);
dfs_st(st,0);
memcpy(dis,dis_st,sizeof(dis_st));
memcpy(fa,fa_st,sizeof(fa_st));
memset(vis,0,sizeof(vis));
for(int x=ed,y=ed;x!=0;x=fa[x]){
while(y&&dis[x]-dis[fa[y]]<=s) y=fa[y];
ans=min(ans,max(dis[y],dis[ed]-dis[x]));
vis[x]=1;
}
for(int i=ed;i;i=fa[i]) dis[i]=0,dfs(i);
for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
cout<<ans;return 0;
}