感觉倍增就是用来加速状态转移的,如果某一种状态转移具有相同的变化状态,并且满足结合律,那么可以用倍增来加速状态转移。
一个经典的应用就是lca,或者说是求某条路径的第k个点。。
对于lca来说很明显他的每次往上走去寻找祖先,每一次的状态的变化规则是相同的,所以我们可以用倍增来优化,把每个点的第2^0..2^1..2^2距离的点处理出来,然后每一次
查询lca的两个点,我们先把高度统一到相同高度,然后再找到最大层数不满足两者祖先相同的高度
下面是模板:
const int M = 30;//n的log
int dep[MX], fa[MX][M], n;
void DFS(int u, int _dep, int _fa)
{
dep[u] = _dep;
fa[u][0] = _fa;
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(v == u || v == _fa) continue;
DFS(v, _dep + 1, u); }
}
/*记得构图后要初始化一遍*/
void presolve()
{ DFS(1, 0, 1);
for(int i = 1; i < M; i++) {
for(int j = 1; j <= n; j++) {
fa[j][i] = fa[fa[j][i - 1]][i - 1]; }
}
} /*倍增法要理解对2的次方的枚举顺序 如果是要走固定步数,那么顺序枚举与i位与为1就行 如果是要求一个临界位置,那么要从大到小枚举 */
int LCA(int u, int v) {
while(dep[u] != dep[v]) {
if(dep[u] < dep[v]) swap(u, v);
int d = dep[u] - dep[v];
for(int i = 0; i < M; i++) {
if(d >> i & 1) u = fa[u][i];
}
}
if(u == v) return u;
for(int i = M - 1; i >= 0; i--)
{
if(fa[u][i] != fa[v][i]) {
u = fa[u][i]; v = fa[v][i]; }
}
return fa[u][0];
}