树形数据结构(一)
树与图的 dfs
树的 dfs
1 | void dfs(int x) { |
树的 dfs 序

1 | vector<int> a; |
树的深度
1 | memset(d, 0, sizeof d); |
树的重心
树的重心非常重要,是点分治中的重要算法

1 | int res = inf, pos; |
图的连通块
1 | int cnt = 0; |
树和图的 bfs
bfs的性质
- bfs 是逐层扩展的,并且每一次出队列的时候,才把队头元素的子节点,放入队列中
所以任何时刻,队列中的元素至多有 个层次的节点
其中一部分节点属于第 层,另一部分属于第 层 - 在访问完第 层节点后,才会访问第 层
- bfs 可以求出 数组, 表示从起点 走到 点
最少需要经过多少点
1 | void bfs() { |
拓扑排序
- 拓扑排序适用于有向无环图 (dag)
- 预处理入度数组 ,把所有 的点入队
- ,检查每一条边
,
Acwing164
用状态压缩来表示集合,不妨设 表示从 出发能够到达的点构成的集合
1 | const int maxn = 30000 + 10; |
树的直径
两次 bfs 求树的直径
- 从 出发执行 ,求出与出发点最远,即 最大的节点
记为 , 就是直径的一端 - 从 出发执行 ,求出最远的点 ,则 为树的一条直径
- 在这个过程中,当每个点第一次被访问的时候,假如当前队列中取出
对于边 ,可以实时维护前驱信息
最后从 回到 ,可以得到具体的直径方案
- 在这个过程中,当每个点第一次被访问的时候,假如当前队列中取出
- 并记录 最远点,
- 并记录 信息
- 并记录 信息,
1 | const int maxn = 400000 + 10; |
- bfs 求树的直径比较适用于无边权,或者边的权值为 的情况
- bfs 求直径很容易求出直径的端点 到树中其他各点的距离
树形 dp 求树的直径

1 | void dp(int x) { |
树的直径的综合应用(一)
1 | const int maxn = 200000 + 10; |
树的直径的综合应用(二)
树网的核
很容易想到一种朴素算法,就是根据树网的核的定义,直接模拟
- 求出树的直径
- 枚举两个端点 ,保证 ,线段 是树网的核
- 模拟
- 对核 上的每个节点标记
- 或者
的时候,可以求出核外的点 与 的距离
对于边 ,执行 - 遍历完成之后,对于 之外的每个节点
,此时 保存的就是节点 到 的距离
,对所有的 取最小值 - ,然后再检查其他的核
最后 即为所求



编程小 tips
直径的方案可以用一个二元组 来保存到 中
方便之后计算
1 | const int maxn = 500000 + 10; |
树的直径的必须边
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 算法小站!
评论









