简单理解树上差分(点,边)
关于树上差分,我在这推荐一道题目POJ 3417 。
题目翻译:https://loj.ac/problem/10131。
树上差分用来解决点的覆盖或者边的覆盖的问题,需分别运用点的差分或者边的差分。
先从例题入手:
给定点数为N,边数为N-1的树(无向边且无重边),先有M条连接a,b的非树边,求每条“树边”被“非树边”覆盖了多少次?
边的差分:
先设一个F【x】,是一个差分数组,表示从X到X的父亲的边被覆盖的次数。对于每一次输入的a , b,朴素算法是O(n)的去遍历每一条边,这样的时间复杂度太高了,我们就可以用差分的思想去优化,就是树上差分,即F[a]++,F[b]++,F[lca(a,b)]-=2;
从X到X的父亲的边被覆盖的次数就是X的子树和了,前缀和的思想。
但是我无法证明这种方法,如果有神犇能证明,麻烦下方评论告知,O(∩_∩)O谢谢。
再来一道例题:
给定点数为N,边数为N-1的树(无向边且无重边),先有M条连接a,b的非树边,求每个“点”被“非树边”覆盖了多少次?
不难看出,这道题只是把“树边”改成了“点”。
点的差分:
设F【x】为x被覆盖的次数。修改F【X】的时候也要变化,还是输入a,b。修改的操作为F[a]++,F[b]++,F[lca(a,b)]--,F[father[lca(a,b)][0]]--;最后一个是LCA(a,b)的父亲。同样,X的子树和就是X点被覆盖的次数。求每个点的子树和只需要DFS一次,复杂度是O(NlogN)的。
实在不理解可以举2个例子模拟一下:
1.从a到b。a,b均不是LCA(a,b)。
2.从a到b。a,b其中之一为LCA(a,b)。
总结一下:树上差分用来解决“点的覆盖”或者“边的覆盖”的问题,是朴素的直接遍历算法的优化,将朴素算法覆盖的时间复杂度O(N*M),直接优化为O(N),时间复杂度十分优秀。