点分治

看来是非学不可了

前言

到目前为止,我们用数据结构处理的大多是序列上的问题。这些问题的形式一般是给定序列中的两个位置 \(l\)\(r\),在区间 \([l,r]\) 上执行查询或修改指令。如果给定一棵树,以及树上的两个节点 \(x\)\(y\),那么与“序列上的区间”相对应的就是“树上两点之间的路径”。我们先不考虑对路径进行修改的操作。本节中介绍的点分治就是在一棵树上,对具有某些限定条件的路径静态地进行统计的算法。

点分治

静态点分治

考虑一个抽象问题:统计树上满足某个条件的路径个数

我们先给这个树随机选一个根,若指定节点 \(p\) 为根,则对 \(p\) 而言,树上的路径就会被分为两类:

  1. 经过根节点 \(p\)
  2. 包含于 \(p\) 的某一棵子树中(不经过根节点)。

根据分治的思想,对于第 2 类路径,显然可以把 \(p\) 的每棵子树作为子问题,递归进行处理。

而对于第 1 类路径,可以从根节点 \(p\) 分成 “\(x\) ~ \(p\)” 与 “\(p\) ~ \(y\)” 两段。

那么这就形成了一个分治结构。

如果我们每次枚举根,并且分治的时候把根去掉,分治剩下的几个子树,那么这种分治方法就叫点分治

点分治的基本思路:

  1. 寻找一个点当做当前树的根

    • 一般使用树的重心
  2. 计算跨过这个根的路径数量或其他信息

    • 一般对一棵子树,先用其中的节点作为路径终点,统计其他子树对其中节点的贡献
    • 然后计算当前子树对其他子树的贡献,修改数据结构。
    • 按存边顺序处理,一个子树统计答案时只有前面的子树对它有贡献,避免算重。(前提是路径起点终点是等价的)
  3. 分治递归计算当前根的子树的贡献

    • 那么不难发现这样就可以统计到所有的路径因为任何一个路径都会在某一次被分到根两棵子树里(或在当前根和子树内),就一定经过了根,会被统计上。
posted @ 2022-10-04 09:55  「ycw123」  阅读(49)  评论(0编辑  收藏  举报