[算法模版]树的重心和直径

[算法模版]树的重心和直径

树的重心

引自OI-WIKI

定义

以树的重心为根时,所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心。

删去重心后,生成的多棵树尽可能平衡。

性质

树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。

把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两个树的重心的路径上。

在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

求法

树的重心可以通过简单的两次搜索求出。

  1. 第一遍搜索求出以每个节点为根的子树中结点数量 \(sz_{u}\)
  2. 第二遍搜索找出使 \(\max_{v\in\operatorname{son}(u)}\{n-sz_{u},sz_{v}\}\) 最小的节点 \(u\)

实际上这两步操作可以在一次遍历中解决。对节点 u 的每一个儿子 v 递归处理,然后以 \(sz_{v}\) 更新 \(u\) 的子节点子树节点数最大值,处理完所有子结点后,判断 u 是否为重心。

(代码来自叉姐)

struct CenterTree {
  int n;
  int ans;
  int siz;
  int son[maxn];
  void dfs(int u, int pa) {
    son[u] = 1;
    int res = 0;
    for (int i = head[u]; ~i; i = edges[i].next) {
      int v = edges[i].to;
      if (v == pa) continue;
      dfs(v, u);
      son[u] += son[v];
      res = max(res, son[v]);
    }
    res = max(res, n - son[u]);
    if (res < siz) {
      ans = u;
      siz = res;
    }
  }
  int getCenter(int x) {
    ans = 0;
    siz = INF;
    dfs(x, -1);
    return ans;
  }
}

参考

http://fanhq666.blog.163.com/blog/static/81943426201172472943638/

https://www.cnblogs.com/zinthos/p/3899075.html

树的直径

定义

树的直径指树上的最长简单路径

求法

随意寻找一个点\(u\)进行\(BFS\),找到的最远点一定为直径的一个端点\(s\)。再从\(s\)开始\(BFS\),找到的最远点一定是直径的另一个端点\(t\)

证明

树的直径,树的重心,树的分冶

参考资料

OI-WIKI

树的直径,树的重心,树的分冶

树的直径

posted @ 2019-11-15 11:19  GavinZheng  阅读(615)  评论(0编辑  收藏  举报