不是题解不是教学!!!
11.7
CSES 1674
给定一颗树求他的子树有多少节点。不提。
CSES 1130
给定一棵树,要求选一些边,要求这些边连接的点没有重复。问最多选多少条边。
简单的树形 dp,对每个点统计以它为根的子树中选它和不选它最多有多少边。转移时,选这个点的至少要搭配一个不选它自己的儿子,这个儿子应该是选儿子减不选儿子最小的点。不选这个点的则没有限制。
11.8
CSES 1131
求树的直径。
之前都用两次 dfs,这次用树形 dp。对于一个点保存它到叶子节点的最长距离,然后父节点选择最长的两个这样的子节点作为自己的答案,取所有节点的最大答案。可以直接更新一个点距离叶子的最长距离,再加上新遍历的到叶子距离,然后与 \(ans\) 取 \(\max\) 是比较简单的实现。
CSES 1132
求树上每个节点到其他节点的最远距离。
换根 dp 可以解决。第一次求以自己为根的子树中的最远距离。第二次求从父亲侧传下来的距离,取其中较大的传给儿子,如果最大的是这个子节点贡献的则传过去次大的。
CSES 1133
求树上每个节点到其他节点的距离之和。
类似上一个,不过同时要记录传过来的节点的数量,每次增加时从只增加一改为增加传过来节点数量,然后传递节点数量还要加一。
CSES 1687
求一个节点的前 k 的祖宗。
树上倍增解决。首先记录每个节点的父亲和深度,并把每个节点的 \(2^i\) 代祖宗设为 0。然后先遍历 \(i\) 再遍历所有点,对于每个点,如果这个点的第 \(2^{i-1}\) 代祖宗存在,那么这个点的第 \(2^i\) 代祖宗就是第 \(2^{i-1}\) 代祖宗的第 \(2^{i-1}\) 代祖宗。注意如果 \(k\) 大于深度则不存在这个祖宗。求答案时,从最大的 \(i\) 开始往下遍历即可。
CSES 1688
求最近公共祖先。
先利用刚刚的方法求出倍增祖宗,然后把深度较大的那个点找到和深度较小的那个点的同一层的祖宗。设较大点为初始点,较小点为目标点。如果这个祖宗就是目标点,那么最近公共祖先就是目标点。否则把祖宗和目标点一直往上找祖宗,只要没跳到同一个点就一直往上同时跳相等长度,最后结果点的父亲就是最近公共祖先。
CSES 1135
求两点之间的距离。
树上差分。先求最近公共祖先。如果目标点就是初始点的祖宗,那么距离就是两者深度之差。否则距离为目标点的深度加初始点的深度减最近公共祖先的深度乘 \(2\)。
11.9
CSES 1136
给定一些路径,每条路径会给包含的节点答案加一,求每个节点的答案。
树上差分。对于每条路径,起始点和目标点加一,最近公共祖先减一,最近公共祖先的父亲减一。最后从叶子往根做前缀和。
CSES 1137
两种操作。改变一个节点的值。求以这个节点为根的子树的值之和。
利用 dfs 序,一个点的 dfs 序加它的子树的大小就是它子树的所有点。得到这个结论后线段树即可。
CSES 1138
两种操作。改变一个节点的值。求这个节点到根的路径上的全部值。
重链剖分。第一遍 dfs 求每个点的子树大小,深度和子树最大的儿子。第二遍 dfs 先走向最大的儿子,并保持链的头不变。跑完之后,跑其他的儿子,并把其他的儿子的链头作为儿子自己。这样最多有 \(logn\) 条链。这样 dfs 后建线段树,每个点就都可以找到自己所在的链开头。然后对于一个节点,求它到链头之间的和加到答案里,然后这个点跳到链头的父亲处,直到跳到根节点的父亲(即 \(0\))即为答案。复杂度为 \(O(nlog^2n)\)。
注意是重儿子是看子树大小而不是深度,如果是深度就变成长链剖分,时间复杂度变成根号了。
CSES 2134
两种操作。改变一个节点的值,求两点间路径上的最大值。
重链剖分。把两个节点中深度较大的那个往上跳一条链并途中统计答案,直到两个节点都到同一条链,最后再求这两个之间的答案。