zoukankan      html  css  js  c++  java
  • 浅谈树上差分

    浅谈树上差分

    【引子】

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

    类比序列问题,其在进行区间修改时,可以用差分将(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似乎并不会卡。

  • 相关阅读:
    C#之枚举
    C#之判断字母大小、字母转ACII码
    C#之BF算法
    md5如何实现encodePassword加密方法
    基本配置及安全级别security-level
    js中“原生”map
    web.xml讲解
    java application指的是什么
    .conf、.bak是什么格式
    Maven系列--web.xml 配置详解
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11625846.html
Copyright © 2011-2022 走看看