树上问题
ShelTeR_Pr1me · · 个人记录
LCA
LCA,最近公共祖先,一般有两种方法求:倍增和树链剖分。
先弄倍增吧。
简单想想,朴素做法如何求 LCA 呢?
如果两个点深度不同,那我们肯定让深度更深的那个往上跳,直到两点深度相同。
这里特判下这两个点所处位置是否相同,如果相同则返回即可。
如果不相同呢?我们要尽量让它们两个尽可能地靠近它们的 LCA,也就是说都让它们跳到它们 LCA 的子节点上。这样它们下一个父亲就是 LCA。
我们发现一步一步地往上爬实在是太慢了,不妨换种思路。
我们知道任何一个数都可以被二进制拆分掉,那么不妨利用这个性质来波倍增解决问题,也就是说我们先拿大的值来尝试,一直到找到它们的 LCA 为止,但我们要首先预处理一下它们的父亲。
树上差分
一般而言,树上问题都可以类比成序列问题来解决。
序列上能差分,树上怎么就不行呢?
如果我们要让树上从
一大堆例题
- 给定一个
n 个点的树,求一点到另一点的路径点权和。
树上问题类比序列问题,在树上求出每一个点到根节点的点权和(类比前缀和)。
这东西又叫做树上差分。
- 给定一个
n 个点的树,有点权,给出m 次询问,每次给三个数x, y, z ,求x, y 之间有多少点值等于z 。
开桶,4 差分,
- 上述问题题面几乎不变,但求
x, y 之间有多少点值小于z 。
把桶换成树状数组。
- 给一棵
n 个节点的树,有m 次询问。每次查询从x 点开始向y 点走,每秒走一步,假设在第i 秒走到了i 点,则答案加 1,求答案。
推一下式子,满足
- 一棵树,要支持单点加,子树和。
DFS 序转换成一个序列,子树变区间。
- 树的直径。
两次 BFS,处理没有负权的情况。