算法总结—树的中心1

树的中心定义

一棵树,当点 \(u\) 为根时,树的深度最小,\(u\) 就是树的中心。

关于树的中心的性质

  • 树的中心最多有两个。如果有两个,一定相邻。

  • 所有点到它最远的点的路径中一定有树的直径。

  • 当书的中心为根时,以根为起点的最长链与次长链构成树的直径。

  • 树的中心一定在树的直径上。

树的中心的求法

首先想到维护最长链 \(dis_{1,u}\),最长链最短时就是树的中心。但是最长链只在子树内,子树外的点没有考虑进去,所以还得维护子树外的最长链 \(up_u\)

\(up_v\) 可以继承 \(up_{fa}\)\(v\)\(fa\) 的一个孩子。但是要避免一种情况:最长链就在 \(u\) 的子树内(\(dis_{1,v}=dis_{1,fa}+w\)),遇到这种情况时,\(up_v\) 就与次长链有关了,所以在之前还需要求出次长链 \(dis_{2,u}\)

【模板】树的中心

求出 \(dis_{1,i},dis_{2,i},up_i\) 后,当 \(\max\{dis_{1,i},up_i\}\) 最小时,\(i\) 就是树的中心。

代码

#include<bits/stdc++.h>
using namespace std;
int dis[5][100005];
int up[100005];
struct edge{
    int v,w;
};
vector<edge>G[100005];
void dfs_down(int u,int father){
    for(auto i:G[u]){
        int v=i.v;
        int w=i.w;
        if(v==father){
            continue;
        }
        dfs_down(v,u);
        if(dis[1][v]+w>dis[1][u]){
            dis[2][u]=dis[1][u];
            dis[1][u]=dis[1][v]+w;
        }else if(dis[1][v]+w>dis[2][u]){
            dis[2][u]=dis[1][v]+w;
        }
    }
    return;
}
void dfs_up(int u,int father){
    for(auto i:G[u]){
        int v=i.v;
        int w=i.w;
        if(v==father){
            continue;
        }
        up[v]=up[u]+w;
        if(dis[1][v]+w==dis[1][u]){
            up[v]=max(up[v],dis[2][u]+w);
        }else{
            up[v]=max(up[v],dis[1][u]+w);
        }
        dfs_up(v,u);
    }
    return;
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v,w;
        cin>>u>>v>>w;
        G[u].push_back({v,w});
        G[v].push_back({u,w});
    }
    dfs_down(1,0);
    dfs_up(1,0);
    int Min=1e9;
    for(int i=1;i<=n;i++){
        Min=min(Min,max(dis[1][i],up[i]));
    }
    for(int i=1;i<=n;i++){
        if(max(dis[1][i],up[i])==Min){
            cout<<i<<"\n";
        }
    }
    return 0;
}
posted @ 2025-03-10 12:24  LRRabcd  阅读(110)  评论(0)    收藏  举报