l u o g u P 2664 树 上 游 戏 \tt luogu\ P2664 \ 树上游戏 luogu P2664 树上游戏
题目大意:
一棵树上每个节点都有颜色,给定一个长度为 n n n 的颜色序列,定义 s ( i , j ) s(i, j) s(i,j) 为 i → j i \to j i→j 的颜色数量。
设 s u m i = ∑ j = 1 n s ( i , j ) sum_i = \sum_{j = 1} ^ n s(i, j) sumi=∑j=1ns(i,j)。求所有的 s u m i sum_i sumi。
这个本质可以看成树上的点对的问题。既然不考虑在线我们可以使用离线算法点分治。
我们需要在 O ( n ) O(n) O(n) 或者 O ( n log n ) O(n \log n) O(nlogn) 的复杂度完成统计以当前节点为 l c a lca lca 的点对的所有贡献。
显然暴力统计是不行的。考虑借鉴一下统计树上距离为 k k k 的点对的方法,开桶进行计算。
首先考虑以根节点为起点的方案数,也就是考虑每一条链上第一个出现的节点,其对于根的贡献是其子树大小。
其子树中每一个点都会产生一次这样颜色的贡献。
为了方便统计我们将根节点的颜色也加上贡献,同时提前打上标记。
之后需要统计点对的贡献。我们不妨将上一次产生贡献的点的贡献记成 f ( i ) f(i) f(i)。那么不产生贡献显然是 f ( i ) = 0 f(i) = 0 f(i)=0。
既然是统计子树中的贡献。考虑遍历每一个子树。
对于每个点的贡献就是。设当前的颜色集合为 S S S。点集合是 T T T,子树的大小是 S i z Siz Siz。
∑ f − ∑ v ∈ T f ( v )