题意:
一棵树有$n$个结点,每个结点都是一种颜色$c_i\leq n$,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。
首先如果$ci$较小,就可以开一个二维数组$dp[N][M_c]$,将每个子树的状态记录下来,可惜空间不够和复杂度过高。但我们发现可以保留一些节点子树的状态,来降低复杂度,但是要保存那些呢?此时就要用到重儿子这个概念。
$Size[x]$:以$x$为根那颗子树的节点数
重儿子:一个根下,节点的$Size$最大
重链:根连接重儿子那条边
轻儿子:不是重儿子的儿子们
轻链:根连接轻儿子那条边
遍历一个节点,我们按以下的步骤进行遍历:
- 先遍历其非重儿子,获取它的$ans$,但不保留遍历后它的状态
- 遍历它的重儿子,保留它的状态
- 再次遍历其非重儿子及其父亲,此时一条重链上的状态就会递归式完善,重链上的重儿子的状态对遍历到的节点进行计算,获取整棵子树的$ans$
根节点到树上任意节点的轻边数不超过$logn$条。我们设根到该节点有$x$条轻边该节点的子树大小为$y$,显然轻边连接的子节点的子树大小小于父亲的一半(若大于一半就不是轻边了),则$y<n/2^x,x<logn$。
又因为如果一个节点是其父亲的重儿子,则他的子树必定在他的兄弟之中最多,所以任意节点到根的路径一个一个走轻链($logn$)或者直接走重链(不会被重复计算+1),所以一个节点的被遍历次数$=logn+1$,总时间复杂度则为 $O(n(logn+1))=O(nlogn)$
模板题$CF600E$
代码
1 |
|
练手题$CF570D$
代码
1 |
|