for(y 是 x 的 儿子)
for(a = 1; a <= K && a <= s[x]; a++)
for(b = 1; b <= s[y] && b + a <= K; b++)
f[x][a + b] = combine(f[x][a], f[y][b]);
其中 s 为子树大小数组。为方便起见,我们把后两层循环称作一次更新。
用慧眼法不难得出上式的复杂度为 \Theta(\min(s[x],K) \times \min(s[y],K)),所以我们可以知道该算法的复杂度为 O(nK^2),其中 n 是树的大小,K 是背包大小。
同时,我们发现循环到 x 的儿子 z 时,设已经处理过的 x 的子树中的点组成的集合为 A(不包含 x), z 的子孙及自己组成的点集为 B,则这次更新的复杂度为 \Theta(|A||B|)。因此,我们可以把复杂度 \Theta(1) 地均摊到每一个点对 (u,v) 上,其中 u \in A,v \in B 。而此时 x 就是 u 和 v 的最近公共祖先,换句话说,就是对于点对 (u,v),当且仅当我们处理的 x 是它们的最近公共祖先时,它们才会贡献 \Theta(1) 的复杂度。所以整体复杂度 O(n^2)。我们把此结论记为结论1,后面会用到。
以上是铺垫,现在开始证明复杂度为 O(nK) 。
我们设大小小于等于 K 的子树为小子树,大小大于 K 的子树为大子树。我们称一个以 x 为根的 小子树 是 极大的 当且仅当以 x 的父亲为根的子树是一颗 大子树。同理,我们称一颗以 x 为根的 大子树 是 极小的 当且仅当所有以 x 的儿子为根的子树都是 小子树 。
我们能够注意到,若一颗 极小的大子树 的根为 x,则以 x 的儿子为根的子树都是 极大的小子树,且一颗 极大的小子树 的根若为 y,则以 y 的父亲为根的子树是一颗 极小的大子树。