Loading docs/graph/tree-centroid.md 0 → 100644 +45 −0 Original line number Diff line number Diff line author: Ir1d, TrisolarisHD, LucienShui, Anguei ## 定义 对于树上的每一个点,计算其所有子树中最大的子树节点数,这个值最小的点就是这棵树的重心。 (这里以及下文中的“子树”都是指无根树的子树,即包括“向上”的那棵子树,并且不包括整棵树自身。) ## 性质 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。 ## 求法 在 DFS 中计算每个子树的大小,记录“向下”的子树的最大大小,利用总点数 - 当前子树(这里的子树指有根树的子树)的大小得到“向上”的子树的大小,然后就可以依据定义找到重心了。 ???+note "参考代码" ```cpp void getCentroid(int u, int fa) { siz[u] = 1; wt[u] = 0; for (int i = head[u]; ~i; i = nxt[i]) { int v = to[i]; if (v != fa) { getCentroid(v, u); siz[u] += siz[v]; wt[u] = max(wt[u], siz[v]); } } wt[u] = max(wt[u], n - siz[u]); if (rt == 0 || wt[u] < wt[rt]) rt = u; // rt 为重心编号 } ``` ## 参考 <http://fanhq666.blog.163.com/blog/static/81943426201172472943638/> <https://www.cnblogs.com/zinthos/p/3899075.html> docs/graph/tree-misc.mddeleted 100644 → 0 +0 −65 Original line number Diff line number Diff line ## 树的重心 ### 定义 以树的重心为根时,所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。 找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心。 删去重心后,生成的多棵树尽可能平衡。 ### 性质 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两个树的重心的路径上。 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。 ### 求法 树的重心可以通过简单的两次搜索求出。 1. 第一遍搜索求出以每个节点为根的子树中结点数量 $sz_{u}$ 2. 第二遍搜索找出使 $\max_{v\in\operatorname{son}(u)}\{n-sz_{u},sz_{v}\}$ 最小的节点 $u$ 。 实际上这两步操作可以在一次遍历中解决。对节点 u 的每一个儿子 v 递归处理,然后以 $sz_{v}$ 更新 $u$ 的子节点子树节点数最大值,处理完所有子结点后,判断 u 是否为重心。 (代码来自叉姐) ```cpp 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> mkdocs.yml +4 −4 Original line number Diff line number Diff line Loading @@ -297,13 +297,13 @@ nav: - 树上问题: - 树基础: graph/tree-basic.md - 最近公共祖先: graph/lca.md - 树的其他问题: graph/tree-misc.md - 树哈希: graph/tree-hash.md - 树的重心: graph/tree-centroid.md - 树链剖分: graph/hld.md - 树上启发式合并: graph/dsu-on-tree.md - 虚树: graph/virtual-tree.md - 树分治: graph/tree-divide.md - 动态树分治: graph/dynamic-tree-divide.md - 虚树: graph/virtual-tree.md - 树上启发式合并: graph/dsu-on-tree.md - 树哈希: graph/tree-hash.md - 矩阵树定理: graph/matrix-tree.md - 有向无环图: graph/dag.md - 拓扑排序: graph/topo.md Loading Loading
docs/graph/tree-centroid.md 0 → 100644 +45 −0 Original line number Diff line number Diff line author: Ir1d, TrisolarisHD, LucienShui, Anguei ## 定义 对于树上的每一个点,计算其所有子树中最大的子树节点数,这个值最小的点就是这棵树的重心。 (这里以及下文中的“子树”都是指无根树的子树,即包括“向上”的那棵子树,并且不包括整棵树自身。) ## 性质 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。 ## 求法 在 DFS 中计算每个子树的大小,记录“向下”的子树的最大大小,利用总点数 - 当前子树(这里的子树指有根树的子树)的大小得到“向上”的子树的大小,然后就可以依据定义找到重心了。 ???+note "参考代码" ```cpp void getCentroid(int u, int fa) { siz[u] = 1; wt[u] = 0; for (int i = head[u]; ~i; i = nxt[i]) { int v = to[i]; if (v != fa) { getCentroid(v, u); siz[u] += siz[v]; wt[u] = max(wt[u], siz[v]); } } wt[u] = max(wt[u], n - siz[u]); if (rt == 0 || wt[u] < wt[rt]) rt = u; // rt 为重心编号 } ``` ## 参考 <http://fanhq666.blog.163.com/blog/static/81943426201172472943638/> <https://www.cnblogs.com/zinthos/p/3899075.html>
docs/graph/tree-misc.mddeleted 100644 → 0 +0 −65 Original line number Diff line number Diff line ## 树的重心 ### 定义 以树的重心为根时,所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。 找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心。 删去重心后,生成的多棵树尽可能平衡。 ### 性质 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两个树的重心的路径上。 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。 ### 求法 树的重心可以通过简单的两次搜索求出。 1. 第一遍搜索求出以每个节点为根的子树中结点数量 $sz_{u}$ 2. 第二遍搜索找出使 $\max_{v\in\operatorname{son}(u)}\{n-sz_{u},sz_{v}\}$ 最小的节点 $u$ 。 实际上这两步操作可以在一次遍历中解决。对节点 u 的每一个儿子 v 递归处理,然后以 $sz_{v}$ 更新 $u$ 的子节点子树节点数最大值,处理完所有子结点后,判断 u 是否为重心。 (代码来自叉姐) ```cpp 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>
mkdocs.yml +4 −4 Original line number Diff line number Diff line Loading @@ -297,13 +297,13 @@ nav: - 树上问题: - 树基础: graph/tree-basic.md - 最近公共祖先: graph/lca.md - 树的其他问题: graph/tree-misc.md - 树哈希: graph/tree-hash.md - 树的重心: graph/tree-centroid.md - 树链剖分: graph/hld.md - 树上启发式合并: graph/dsu-on-tree.md - 虚树: graph/virtual-tree.md - 树分治: graph/tree-divide.md - 动态树分治: graph/dynamic-tree-divide.md - 虚树: graph/virtual-tree.md - 树上启发式合并: graph/dsu-on-tree.md - 树哈希: graph/tree-hash.md - 矩阵树定理: graph/matrix-tree.md - 有向无环图: graph/dag.md - 拓扑排序: graph/topo.md Loading