码迷,mamicode.com
首页 > 其他好文 > 详细

浅谈树上差分

时间:2019-10-05 22:47:32      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:sim   重复   行修改   fat   csp   就是   存在   如何   span   

浅谈树上差分

【引子】

我们遇到一些关于树的问题时,往往需要我们统计一些树上的信息,比如子树和,路径边覆盖、点覆盖(目前没见过别的类型)。暴力的解法当然是遍历逐个点对其权值进行修改。

类比序列问题,其在进行区间修改时,可以用差分将\(O(n)\)复杂度降为\(O(1)\)。在树上我们是对一条链进行处理,那差分在树上可不可用呢?答案是肯定的。

【从序列到树】

在一个序列上进行差分的操作,相信各位都十分熟悉:假设当前我们要对一个序列的\(l\sim r\)区间的每个数执行\(+k\)操作,那么对于差分数组,我们在\(l\)位置\(+k\),表示从\(l\)开始有一个\(+k\)的影响,在\(r+1\)位置\(-k\),表示在\(r+1\)这个位置影响被消除。这个影响是从序列首端传递到序列尾端的

首先我们要明白,对于一条树上的链,假设其起点为\(s\),终点为\(t\),其一定可以分为两部分:\(s\sim lca(s,t),lca(s,t)\sim t\)。或者说,对于任意一棵树,对于点对\((s,t)\),它所表示的路径是唯一的

感性的理解一下,由于树上的任意点只存在一个父节点,那么如果这个点不断向父节点移动,路径就是唯一的。那么对于一个点对,这两个点不断向上移动,减少深度的时候,就一定会相遇,我们叫这个相遇的点“最近公共祖先”,也就是LCA。

【树上差分】

那么如果我们将差分技巧拓展到树上会如何呢?差分的核心思想是某种影响的产生与消除。显然,对于一条树链,它的影响产生于\(s\),消除于\(t\)。但是,一棵树上有那么多条链,如果这样进行差分的话,最后如何统计整棵树的点的权值呢?

既然单独对一条条链进行差分无法达到要求,那我们不妨把整棵树作为一个差分的对象。上文提到,任意点的父节点只有一个,也就是说任意点到根节点的路径也是唯一的。如果我们把根节点那边类比做序列尾端,把叶子节点那边类比做序列首端,那这样的话,这个影响不就能自底向上传递了吗?

具体地说,如果我们有差分数组\(c[]\),对于任意一棵树,假设我们要对\(s\sim 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],i\in son\)。这个信息是从叶子节点逐层向上传递的。

对于任意多个点对\((s,t)\)的询问,我们重复上述差分操作,最后进行自底向上的统计即可。

讨论完了点覆盖的情形,我们来考虑边覆盖。点覆盖与边覆盖唯一的区别就在于当前子树的根节点是否计算在内。显然,点覆盖的情况是包含根节点的,而边覆盖是不包含的。因此,我们只需稍稍修改差分操作:在\(c[s]+1\),在\(c[t]+1\),在\(c[lca(s,t)]-2\)。最后进行统计即可。


几道例题

P3128

一道裸题,适合入门树上差分,非常简单。

P2608

一道结合了一点点别的东西的树上差分裸题,需要一点思维量,还算比较简单。

P4556

涉及到线段树合并,建议去学,正常难度的题目。当然如果你会树剖就当我没说。

P1600

啊我死了。

【扯点淡】

最近真是越来越常考树论了。。。特别是树上差分老是考,我的建议是学树剖或者LCT,便于成为调参带湿。其实会树上差分也差不多够用了,多学点也没负面影响。主要是倍增LCA常数感人,好在NOIpCSP似乎并不会卡。

浅谈树上差分

标签:sim   重复   行修改   fat   csp   就是   存在   如何   span   

原文地址:https://www.cnblogs.com/DarkValkyrie/p/11625846.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!