树上背包复杂度证明
一直没细想这个问题,证了下才发现并不难。
\(siz[x]\)表示子树\(x\)的大小,\(y_i\)为\(x\)的第\(i\)个儿子,\(f(y_i)=\sum\limits_{j=1}^{i-1} siz[y_j]\),运算次数为:
\[ \sum\limits_{x=1}^n \sum\limits_{i=1}^m \sum\limits_{j=0}^{f(y_i)+siz[y_i]} \sum\limits_{k=max(0,j-f(y_i))}^{min(j,siz[y_i])} O(1)
\]
对于每个\(y_i\),其运算次数如下图:

其对答案的贡献是\((siz[f(y_i)]+1)\times siz[y_i]\),对所有\(y_i\)的贡献求和可以看出其实就是\(O(\sum_{i<j} siz[y_i]\times siz[y_j])\),即:在子树\(x\)内,有多少个点对的\(LCA\)是\(x\)。(严格来说这里的点对不包括含\(x\)的点对,但是不影响复杂度,所以这么表述也问题不大),并且由于不在子树\(x\)内的点,其\(LCA\)也不可能是\(x\),所以问题就是在这棵树中有多少个点对的\(LCA\)是\(x\)。
那么最终的答案就是\(O(\sum_{x=1}^n x是多少个点对的LCA)\),从点对的角度考虑就是每个点对提供\(O(1)\)的贡献,答案就是\(O(n^2)\)。
如果第二层for循环写成for (int k = 0; k <= j; ++k),那么上图就从平行四边形变成了矩形,每个点多提供了\(O(siz[i]^2)\)的贡献,复杂度就是\(O(n^3)\),从点对的角度考虑就是每个点对\((i,j)\)的贡献等于\(O(i,j的公共祖先数量)\)。

浙公网安备 33010602011771号