D49 树的直径 两次DFS+双指针 P2491 [SDOI2011] 消防

D49 树的直径 P2491 [SDOI2011] 消防_哔哩哔哩_bilibili 

P2491 [SDOI2011] 消防 - 洛谷

P1099 [NOIP 2007 提高组] 树网的核 - 洛谷  雷同

// 两次DFS+双指针 O(n)
#include<bits/stdc++.h>
using namespace std;

const int N=300010;
int n,s,p,r,d[N],pre[N],col[N];
vector<pair<int,int>> e[N];

void dfs(int u,int fa){
  if(d[u]>d[p]) p=u; //记录最远点
  pre[u]=fa; //记录路径
  for(auto [v,w]:e[u]){
    if(v==fa||col[v]) continue;
    d[v]=d[u]+w;
    dfs(v,u);
  }
}
int main(){
  ios::sync_with_stdio(0);
  cin>>n>>s;
  for(int i=1,x,y,z;i<n;i++){
    cin>>x>>y>>z;
    e[x].emplace_back(y,z);
    e[y].emplace_back(x,z);
  }
  dfs(1,0);
  d[p]=0;
  dfs(p,0); r=p;
  
  int ans=2e9;
  for(int i=r,j=r;i;i=pre[i]){ //直径上的答案
    while(d[j]-d[i]>s) j=pre[j];
    ans=min(ans,max(d[i],d[r]-d[j]));
  } 
  for(int i=r;i;i=pre[i])col[i]=1; //直径染色
  for(int i=r;i;i=pre[i]){ //直径外的答案
    p=i;d[i]=0;
    dfs(i,pre[i]);
  }
  for(int i=1;i<=n;i++)ans=max(ans,d[i]);
  printf("%d\n",ans);
}

 

posted @ 2024-09-16 10:24  董晓  阅读(269)  评论(0)    收藏  举报