DSU on tree
DSU on Tree
DSU on Tree 是指在树上利用类似于并查集的启发式合并的方法处理一类统计的问题。比如这些问题:对于每一个子树T,计算:
1)T中结点的值组成的众数
2)T中不同的结点的值的个数
3)T结点的值从小到大排序后最接近T的根结点的值
以子树中不同的结点的值的个数为例,如果直接对每一个子树T都从T的根结点用一次深度优先搜索遍历,时间复杂度会非常大(O(n2)),大部分图论题n都高达 105 ,显然不能用这种方法。
如果在计算以父结点P为根的子树的问题时候,能重复利用之前已经计算过的,以P的儿子为根的子树的信息,就可以减少一些遍历次数。但是由于有多个以儿子结点为根子树(T1、T2、……、Tn),为了计算每一个子树Ti的答案,必须舍弃其他子树的信息(否则就把其他子树的答案累加进去了,导致答案错误)。仔细观察后发现我们可以利用最后一个儿子结点为根的子树的信息。
如:为了计算以图中P结点为根的子树中颜色的数量,我们可以先求以s1为根的子树中颜色的数量、以s2为根的子树中颜色的数量、以s3为根的子树中颜色的数量。以前面两个儿子为根的子树(T1、T2)中的信息就被丢弃了,因为在计算第s2为根的子树时不能统计以s1为根的子树的颜色的数量,计算以s3为根的子树中颜色的数量的时候也必须丢弃以s2为根的子树留下的信息。只剩下以s3为根的子树留下的信息。
为了计算父结点P的答案,我们还必须重新统计以前两个儿子为根的子树中的结点的信息。为了让代价最小,我们可以让子结点数量最大的儿子最后计算。于是计算的过程就是:
计算过程
先遍历结点数量少的儿子并丢弃信息(记为A),再遍历结点数量多的儿子并保留信息(记为B),再回去遍历数量少的儿子(用于计算P的答案)并保留信息(记为C)。
复杂度
这种贪心方法很明显,它的时间复杂度有多大却不明显。我们可以来考虑每一个结点会被遍历几次。一个结点只能在上面过程中(A)、(B)、(C)中被遍历,我们把过程B经过的边加粗。
通过观察可以发现,在第二层中,每一个结点会遍历 次(只用于计算自己的答案+用于计算别人的答案,x就是(A)过程中丢弃信息的次数。我们可以得到一个结点S的信息被丢弃的次数就是从根结点R到S的路径上细边的个数。
现在问题就是确定 的上界,从而确定时间复杂度。
假设整个树有n个结点,那么,每个细边的子树(s1、s3)大小应该是小于等于P的大小1/2的。我们记细边的子树大小为 ( ),那么 ( 是从根结点R到s3的路径上细边的个数)。于是 ,可以得到 。
每一个结点最多被遍历 次,如果每次遍历时间复杂度是 ,那么总的时间复杂度就是 。