0
点赞
收藏
分享

微信扫一扫

树网的核[有关树的直径]

刘员外__ 2022-07-12 阅读 52

树网的核[有关树的直径]_#define

树网的核[有关树的直径]_#define_02 

 

树网的核[有关树的直径]_#define_03

树网的核[有关树的直径]_i++_04

输入样例#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

树网的核[有关树的直径]_#define_05

若x的偏心距最大,那么直径应该就是x--ed了

同理,当核是一条路径时,x上头和y下头的所有点都是不行的,所以这种情况的偏心距应该为

Max(x到st的距离,y到ed的距离,(x,y)之间任意一个节点到以该节点为根的最远距离

树网的核[有关树的直径]_#define_06

因此我们先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;
}

 


举报

相关推荐

0 条评论