浅谈树上差分
Posted darkvalkyrie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈树上差分相关的知识,希望对你有一定的参考价值。
浅谈树上差分
【引子】
我们遇到一些关于树的问题时,往往需要我们统计一些树上的信息,比如子树和,路径边覆盖、点覆盖(目前没见过别的类型)。暴力的解法当然是遍历逐个点对其权值进行修改。
类比序列问题,其在进行区间修改时,可以用差分将(O(n))复杂度降为(O(1))。在树上我们是对一条链进行处理,那差分在树上可不可用呢?答案是肯定的。
【从序列到树】
在一个序列上进行差分的操作,相信各位都十分熟悉:假设当前我们要对一个序列的(lsim r)区间的每个数执行(+k)操作,那么对于差分数组,我们在(l)位置(+k),表示从(l)开始有一个(+k)的影响,在(r+1)位置(-k),表示在(r+1)这个位置影响被消除。这个影响是从序列首端传递到序列尾端的。
首先我们要明白,对于一条树上的链,假设其起点为(s),终点为(t),其一定可以分为两部分:(ssim lca(s,t),lca(s,t)sim t)。或者说,对于任意一棵树,对于点对((s,t)),它所表示的路径是唯一的。
感性的理解一下,由于树上的任意点只存在一个父节点,那么如果这个点不断向父节点移动,路径就是唯一的。那么对于一个点对,这两个点不断向上移动,减少深度的时候,就一定会相遇,我们叫这个相遇的点“最近公共祖先”,也就是LCA。
【树上差分】
那么如果我们将差分技巧拓展到树上会如何呢?差分的核心思想是某种影响的产生与消除。显然,对于一条树链,它的影响产生于(s),消除于(t)。但是,一棵树上有那么多条链,如果这样进行差分的话,最后如何统计整棵树的点的权值呢?
既然单独对一条条链进行差分无法达到要求,那我们不妨把整棵树作为一个差分的对象。上文提到,任意点的父节点只有一个,也就是说任意点到根节点的路径也是唯一的。如果我们把根节点那边类比做序列尾端,把叶子节点那边类比做序列首端,那这样的话,这个影响不就能自底向上传递了吗?
具体地说,如果我们有差分数组(c[]),对于任意一棵树,假设我们要对(ssim t)这条路径上的所有点执行(+1)操作,那么我们就在(c[s]+1),在(c[t]+1),在(c[lca(s,t)]-1),在(c[father(lca(s,t))]-1)。然后我们自底向上传递信息,意即对于节点(x),假设它的子节点集合为(son),子树和为(ans[x]),那么有(ans[x]=c[x]+sum c[i],iin son)。这个信息是从叶子节点逐层向上传递的。
对于任意多个点对((s,t))的询问,我们重复上述差分操作,最后进行自底向上的统计即可。
讨论完了点覆盖的情形,我们来考虑边覆盖。点覆盖与边覆盖唯一的区别就在于当前子树的根节点是否计算在内。显然,点覆盖的情况是包含根节点的,而边覆盖是不包含的。因此,我们只需稍稍修改差分操作:在(c[s]+1),在(c[t]+1),在(c[lca(s,t)]-2)。最后进行统计即可。
几道例题
P3128
一道裸题,适合入门树上差分,非常简单。
P2608
一道结合了一点点别的东西的树上差分裸题,需要一点思维量,还算比较简单。
P4556
涉及到线段树合并,建议去学,正常难度的题目。当然如果你会树剖就当我没说。
P1600
啊我死了。
【扯点淡】
最近真是越来越常考树论了。。。特别是树上差分老是考,我的建议是学树剖或者LCT,便于成为调参带湿。其实会树上差分也差不多够用了,多学点也没负面影响。主要是倍增LCA常数感人,好在NOIpCSP似乎并不会卡。
以上是关于浅谈树上差分的主要内容,如果未能解决你的问题,请参考以下文章