倍增算法

树上倍增

倍增算法就是通过倍增快速查找的算法。它在树的问题上比树链剖分处理得要快而且简单。

它的核心公式就是fa[x][j]=fa[fa[x][j-1]][j-1] / fa[x][j+1]=fa[fa[x][j]][j].为了更好地理解这个公式,我打了以下表格:

  0 1 2 3
1 0 0 0 0
2 1(1+2^0) 0 0 0
3 2 1(1+2^1) 0 0
4 3 2 0 0
5 4 3 1(1+2^2) 0
6 5 4 2 0
7 6 5 3 0
8 7 6 4 0
9 8 7 5 1(1+2^3)

看得出来,横行表示的是2的幂数,也就是fa[x][j]中的j。

将j和x颠倒似乎能优化。

那么每次dfs一个点的时候,我们先记录fa[x][0]为该点的直接父亲,然后将它初始化:

for (register int i=0;fa[x][i];++i) fa[x][i+1]=fa[fa[x][i]][i];

若要求两点的LCA,首先要记录它们的深度,然后倍增:

inline int LCA(int u,int v)
{
    if(dep[u]<dep[v])swap(u,v);
    for(R int i=0;i<=16;i++)
        if((dep[u]-dep[v])&(1<<i))u=fa[u][i];
    if(u==v)return u;
    for(R int i=16;i>=0;i--)
        if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
    return fa[u][0];
 } 

毕竟,指数爆炸可是很快的。这是一个清清楚楚的logn的复杂度。

posted @ 2020-06-27 22:01  Star_Cried  阅读(929)  评论(0编辑  收藏  举报