树形 dp 做题记录
-
考虑每一条边的贡献,就会发现这个贡献其实只和子树内的黑点的数量有关
-
那么设 \(dp[u][num]\) 表示 \(u\) 节点子树内有 \(num\) 个黑点的最大收益
-
可以发现最后的图就是一个基环森林,考虑一颗基环树怎么解决
-
对于一颗基环树,考虑找到环上的一个点,然后断开换上的一条边
-
然后就是一颗树了,对于一棵树就很好求了,最后我们强制根节点不选,那么答案仍然是合法的
-
还有种情况就是强制那个和根之前相连的节点不选,然后再做一次,这样答案仍然合法
-
看到一个条件,对于一个乡村可以通过不超过 40 条路到达首都
-
设 \(f[u][i][j]\) 表示节点 \(u\) 上面修建了 \(i\) 条公路和 \(j\) 条铁路,子树种的最小值
-
那么每次先便遍历子树,然后对于自己枚举 \(i,j\) ,然后有两种选择,一种是修建左边,一种是修建右边
- 对于一个节点,自己祖先的路径只会统一修改自己的子树,所以我们对于每个节点,都要将自己所有的儿子修改到同一个时间
-
因为每条路要被走 2 次,所以一开始权值乘二
-
对于每个节点维护 \(dp[u][time]\) 表示从这个节点下去还剩 \(time\) 的时间能得到的最多的画
-
这个路径一定是在直径上,那么就可以把这个题目抽象成一个序列(直径)上的问题
-
可以考虑用尺取法确定一个区间,对于这个区间的最大值就是左边右边中间,左右的可以预处理,对于中间的可以考虑单调队列维护
-
那么整体的复杂度就是 \(O(n)\)
-
我一开始想的是二分,但是麻烦一点
-
这个题目一个很不好做的点在于有后效性,也就是当前的选择会影响到后面的选择
-
对于一个节点为开始的话,肯定是先点亮自己,然后点亮一颗子树,再点亮另一颗子树,然后再点亮父亲,点亮父亲的另一颗子树,点亮父亲的父亲....
-
对于这个节点不只要考虑子树中要是最小,还要考虑从子树中的一个叶节点到达父亲的一个路径长度
-
既然有后效性,那么我们就将这个后效加入到状态中(事实上对于这一类有后效的 dp 可以考虑加上后效这一状态,或者更简单的直接加上会对后面造成的影响)
-
对于一个叶子节点,下一步要么走到一个祖先,要么走到一个祖先的另一个儿子
-
那么对于两者我们都保存,因为是一个完全二叉树,所以只会有 \(\log\) 的祖先
-
设 \(f[u][i]\) 表示节点 \(u\) 遍历自己的子树完了后从子树中的一个叶子节点,到达第 \(i\) 个祖先的最小价值
-
设 \(g[u][i]\) 表示节点 \(u\) 遍历自己的子树完了后从子树中的一个叶子节点到达第 \(i\) 个祖先的另一个儿子的最小价值
-
状态设出来了,转移方程就从儿子转移
-
考虑最后一个节点作为第一个点亮的节点,那么这个节点肯定是先点亮自己的子树,然后点亮父亲,点亮父亲的另一个儿子,然后点亮父亲的父亲
-
而这个过程很明显可以用我们刚刚求的数组来解决
-
对于每个节点都假设为最初的节点
-
总的复杂度就是 \(O(n\log n)\)
一些小 trick
-
看到树了,考虑一下树形 dp
-
一般都会有结点这个维度,一般都是考虑一个子树,然后考虑怎么从儿子转移
-
完全二叉树的高度是 \(\log\)