注:学习倍增需要对二进制有一定了解,并且清楚十进制与二进制的关系
倍增是一种预处理的算法,他用来解决形如:一个状态往后走 k k k 步会走到什么状态,那么此时我们解决这个问题的思路是处理出每一个状态走 2 j 2^j 2j 步以后走到的状态,此时我们将 k k k 进行二进制拆分,把他拆成多个二的整数次幂的和 2 a 1 + 2 a 2 + . . . + 2 a m = k 2^{a_1} + 2^{a_2} + ... + 2^{a_m} = k 2a1+2a2+...+2am=k,请注意,这个问题必须要具有累加性与合并性,即这个状态先走 2 a 1 2^{a_1} 2a1 步,再走 2 a 2 2^{a_2} 2a2 步,…,再走 2 a m 2^{a_m} 2am 后走到的状态就是这个状态往后走 k k k 步的状态。
温馨提示:你可以先去看看序列上的倍增
题意简述:
给出一棵 n n n 个节点的树和 m m m 个询问,对于第 i i i 个询问包含两个整数 u i , k i u_i, k_i ui,ki 表示要查询节点 u i u_i ui 的第 k i k_i ki 代祖先的编号,如果不存在输出 − 1 -1 −1
数据范围:
1 ≤ n , m ≤ 2 × 1 0 5 1 \leq n, m \leq 2 \times 10^5 1≤n,m≤2×105
在最开头说的还记得吗?我们首先来观察这道题有没有累加性,很显然是有的,比如 k i = 2 k_i = 2 ki=2,那么点 u i u_i ui 的第 2 2 2 代祖先即 u i u_i ui 的第 1 1 1 代祖先的第 1 1 1 代祖先,比较容易看出来这个问题是具有累加性与合并性的,所以我们考虑把 k k k 拆分为二的整数次幂,这个东西直接看 k k k 的二进制就行了。那么此时我们的问题就是对于任意节点 u u u 我们怎么知道他的 2 k 2^k 2k 代祖先呢( k k k 为任意整数)。很显然我们可以使用一个类似动态规划的思想,即把问题: u u u 的 2 k 2^k 2k 代祖先划分成子问题来合并,得到当前问题的答案。前面我们说了,这个问题具有合并性和累加性,所以我们考虑利用累加性把第 k k k 代拆分成多个我们可以算出来的东西,进行合并得到当前的问题。很显然 u u u 的 2 k 2^k 2k 代祖先就等于是 u u u 的 2 k − 1 2^{k-1} 2k−1 代祖先的 2 k − 1 2^{k-1} 2k−1