树的结构

内容

  • 树的直径
  • 树的重心
  • 重心分解

树的直径

直径

树上的一条最长的路径。

如何看待直径

center

如何看待直径

  • 把直径水平放置
  • 剩余部分成为以直径上的点为根的子树

如何看待直径

  • 虚线下面没有顶点

如何看待直径

  • 虚线下面没有顶点

→ 红色的部分是直径

直径的性质

  • 如果我们寻找距离某个点 最远的点……

直径的性质

  • 对于任意顶点 ,直径的某个端点一定是距离 最远的点。

→ 红色的部分才是直径

求直径的方法

  • 对于任意顶点 ,直径的某个端点一定是距离 最远的点。

→ 反过来,对于任意顶点 ,任何一个距离 最远的点一定是直径的端点。

求直径的方法

  • 一旦找到了直径的一个端点,由于直径是最长的路径,距离那个点最远的点就是直径的另一个端点。

求直径的方法

  1. 任选一个顶点
  2. 用 BFS 找出一个距离点 最远的点,设它是顶点
  3. 用 BFS 找出一个距离点 最远的点,设它是顶点
  4. 路径 就是直径。

时间

问题

这个树的直径有哪些?

树的中心(直径长度是偶数时)

  • 直径中心的那个顶点。
  • 所有直径都经过树的中心。

树的中心(直径长度是 时)

  • 一些以中心为根的高度不超过 的子树。

直径的个数?

树的中心(直径长度是 时)

  • 一些以中心为根的高度不超过 的子树。

直径的个数?

→ 从两个不同的子树中各选一个深度是 的点,选择的方法数。

:第一个子树里,深度是 的点的个数。

树的中心(直径长度是奇数时)

  • 直径中心的那条边

树的中心(直径长度是 时)

  • 直径中心的那条边
  • 所有直径都通过树的中心

→ 由于虚线的限制,不通过树的中心的路径,长度不超过

树的中心(直径长度是 时)

  • 由中心和以中心的端点为根的两个高度等于 的子树组成的结构。

直径的个数?

→ (左侧深度等于 的顶点个数) (右侧深度等于 的顶点个数)

树的直径和中心另一种看法

center

树的重心

重心是什么?

  • 如果我们把某个顶点 从树中删除……

重心是什么?

  • 如果把某个顶点 从树中删除,树会分解成若干连通块。
  • 使各连通块的 size 的最大值
    )最小的顶点 就是树的重心。

重心只有一个的情形

  • 如果把某个顶点 从树中删除,树会分解成若干连通块。
  • 使各连通块的 size 的最大值
    )最小的顶点 就是树的重心。

重心只有一个 若把 向最大的连通块(size 4)的方法移动一步,将造成一个更大的连通块(size 5)

最大连通块(size 4)的大小不到整个树(size 9)的一半。

如果不是这样,是什么情形呢?

重心有两个的情形

  • 若重心不止一个,则有一条边把图分成大小相同的两半。
  • 此时有两个重心。
  • 有时候把中间那条边当作重心更为方便。

重心是什么?(再谈)

  • 如果把某个顶点 从树中删除,树会分解成若干连通块。
  • 使各连通块的 size 的最大值
    )最小的顶点 就是树的重心。
  • 顶点 ,删除它之后,最大的连通块的大小不超过整个树大小的一半,就是重心。

(这两个定义等价)

重心的性质

  • 删除重心之后,剩下的每个连通块的大小不超过原来树大小的一半

重心的求法

  1. 任选一个点作为根,考虑有根树。
  2. 求出每个子树的 size
  3. 子树 size 不到整个树 size 一半的顶点不是重心。

重心的求法

  1. 任选一个点作为根,考虑有根树。
  2. 求出每个子树的 size
  3. 子树 size 不到整个树 size 一半的顶点不是重心。
  4. 剩下的顶点中,子树 size 最小点的那个是重心。
  5. 如果这个点的子树 size 恰是整个树的一半,那么它的父节点也是重心。

重心的求法

  1. 任选一个点作为根,考虑有根树。
  2. 求出每个子树的 size。
  3. 从根出发,走到重心。
    • 若当点有一个子节点 size 超过整个树的一半,走到那个点。
    • 否则当前点就是重心,结束。

重心的求法

vector<int> g[maxn];
int sz[maxn];
void get_size(int u, int p) {
    sz[u] = 1;
    for (int v : g[u])
        if (v != p) {
            dfs(v, u);
            sz[u] += sz[v];
        }
}

int n;
int centroid(int u, int p) {
    for (int v : g[u])
        if (v != p && sz[v] * 2 > n)
            return centroid(v, u);
    return u;
}

重心的性质

重心到每个点的距离之和最小。

考虑一个有 个点树,对树上每个点 ,定义

其中 表示点 和点 的距离。

那么,当且仅当 是树的重心时 取到最小值。

证明?

问题

有一个有 个点的树、每个点上有一个人,人 在点 上。选择一个 的排列 。对于每个 ,人 从点 移动到点 ,费用是每个人的移动距离之和。求费用的最大值。

重心分解