20251122 - 树的直径、重心、中心

树的基本概念

树是一种典型的非线性数据结构,是一种特殊的图,最大的特点就是没有环,所以他有许多良好的性质(比如可以 dp)。更绝的是,考的题目一般都很难!

树的直径

树的直径是指树中任意两点间的最长距离。

如何求出直径

方法零:

枚举每一个点,记录每一个点到其他点的距离,再求最大值。

时间复杂度:\(O((n + m)^2)\)

方法一:

先从任一点做一遍 dfs,求出距离最长的点,再从这个点再求一遍 dfs,求最长距离。

时间复杂度:\(O(n+m)\)

可这个算法 和Dijkstra一样,不能处理负权边,那可怎么办?SPFA 树形 dp

方法二:

在 dfs 的过程中,求出最长路和次长路,再相加就是直径的长度。

但不知道能不能求直径的两个端点

时间复杂度:\(O(n+m)\)

树的重心

树的重心就是把一个点扣掉后,剩下的子树的大小最大值最小的点就是树的重心。

如何求出重心

方法零:

枚举每一个点,做一次 dfs 即可。

时间复杂度:\(O((n + m)^2)\)

方法一:

记录 size 数组表示子树的大小,那么其他的大小就是 \(n-size[u]\),这样子就可以求出重心了!

时间复杂度:\(O(n+m)\)

其实就是换根dp

树的中心

到其他点的距离最大值最小的点叫做树的中心。

方法一:

树形 dp 时记录一下即可。

方法二:

找到直径端点,在往上跳呀跳呀跳,在按照奇偶性搞一下就好了。

例题:

树的直径(两次dfs)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int N = 1e5 + 7;
const int P = 998244353;
const int inf = (1 << 30);
template<class T> void read(T &x){
  x = 0;int f = 1;char ch = getchar();
  while(!(ch >= '0' && ch <= '9')){if(ch == '-') f = -f;ch = getchar();}
  while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
  x *= f;
}
int n;
vector<int>edges[N];
int dist[N];
int max_(){
  int id = 0,mx = 0;
  for(int i = 1;i <= n;i++){
    if(dist[i] > mx){
      mx = dist[i];
      id = i;
    }
  }
  return id;
}
inline void dfs(int u,int from){
  for(auto v : edges[u]){
    if(v == from) continue;
    dist[v] = dist[u] + 1;
    dfs(v,u);
  }
}
int main(){
  read(n);
  for(int i = 1;i < n;i++){
    int x,y;
    read(x),read(y);
    edges[x].push_back(y);
    edges[y].push_back(x);
  }
  dfs(1,1);
  int id = max_();
  dist[id] = 0;
  dfs(id,id);
  id = max_();
  printf("%d\n",dist[id]);
  return 0;
}

树的重心(老师怎么突然改题啊!)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int N = 1e5 + 7;
const int P = 998244353;
const int inf = (1 << 30);
template<class T> void read(T &x){
  x = 0;int f = 1;char ch = getchar();
  while(!(ch >= '0' && ch <= '9')){if(ch == '-') f = -f;ch = getchar();}
  while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
  x *= f;
}
int n,siz[N],pre[N],dep[N];
vector<int>edges[N];
inline void dfs(int u){
  siz[u] = 1;
  for(auto v : edges[u]){
    if(pre[u] == v) continue;
    pre[v] = u;
    dep[v] = dep[u] + 1;
    dfs(v);
    siz[u] += siz[v];
  }
}
int main(){
  read(n);
  for(int i = 1;i < n;i++){
    int x,y;
    read(x),read(y);
    edges[x].push_back(y);
    edges[y].push_back(x);
  }
  pre[1] = -1;
  dfs(1);
  int now_ans = inf,id;
  for(int i = 1;i <= n;i++){
    int res = 0;
    for(auto v : edges[i]){
      if(pre[v] == i){
        res = max(res,siz[v]);
      }else{
        res = max(res,n - siz[i]);
      }
    }
    if(res < now_ans){
      id = i;
      now_ans = res;
    }
  }
  printf("%d ",id);
  dep[id] = 0;
  pre[id] = -1;
  dfs(id);
  printf("%d\n",accumulate(dep+1,dep+n+1,0));
  return 0;
}

树的中心

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const int N = 1e5 + 7;
const int P = 998244353;
const int inf = (1 << 30);
template<class T> void read(T &x){
  x = 0;int f = 1;char ch = getchar();
  while(!(ch >= '0' && ch <= '9')){if(ch == '-') f = -f;ch = getchar();}
  while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
  x *= f;
}
int n;
vector<int>edges[N];
int dist[N],fa[N];
int max_(){
  int id = 0,mx = 0;
  for(int i = 1;i <= n;i++){
    if(dist[i] > mx){
      mx = dist[i];
      id = i;
    }
  }
  return id;
}
inline void dfs(int u,int from){
  for(auto v : edges[u]){
    if(v == from) continue;
    fa[v] = u;
    dist[v] = dist[u] + 1;
    dfs(v,u);
  }
}
int main(){
  read(n);
  for(int i = 1;i < n;i++){
    int x,y;
    read(x),read(y);
    edges[x].push_back(y);
    edges[y].push_back(x);
  }
  dfs(1,1);
  int id = max_();
  dist[id] = 0;
  dfs(id,id);
  id = max_();
  int dist_max = dist[id];
  // printf("%d\n",dist_max);
  if(!(dist_max & 1)){
    for(int i = 1;i <= dist_max / 2;i++)
      id = fa[id];
    printf("%d\n",id);
  }else{
    for(int i = 1;i <= (dist_max - 1) / 2;i++) // 跳啊跳啊跳!
      id = fa[id];
    printf("%d %d\n",min(id,fa[id]),max(id,fa[id]));
  }
  return 0;
}

posted @ 2025-11-23 11:46  AKCoder  阅读(22)  评论(0)    收藏  举报