【10.9】LCA

补一发LCA

LCA基本步骤

在有根树一棵树上,先将两点跳到相同的高度(deep),在一起向上跳,直到两点相遇。

倍增优化

倍增,按 \(2\) 的指数级别向上跳。

\(deep[u]\) 为点 \(u\) 的深度, \(fa[u][i]\) 为点 \(u\)\(2^i\) 级祖先。

预处理:

void getDeep(int u,int f){ //u当前节点,f节点的父亲
    vis[u]=1;
    dep[u]=dep[f]+1;
    fa[u][0]=f; //u的第1级祖先是父亲
    for (int i=1;(1<<i)<=dep[u];i++){ //更新祖先
        fa[u][i]=fa[fa[u][i-1]][i-1]; //2^(i-1)+2^(i-1)=2^i
    }
    for (int v:e[u]){
        if (vis[v]) continue;
        getDeep(v,u);
    }
    vis[u]=0;
    return;
}

LCA:

int LCA(int u,int v){
    if (dep[u]<dep[v]) swap(u,v);
    int cha=dep[u]-dep[v],logcha=log(cha)/log(2)+0.5;
    for (int i=0;i<=logcha;i++){
        if (cha&(1<<i)) u=fa[u][i]; //注意是fa[u][i]而不是fa[u][1<<i]
    }
    if (u==v) return u;
    int logdep=log(dep[u])/log(2)+0.5;
    for (int i=logdep;i>=0;i--){
        if (fa[u][i]==fa[v][i]) continue; //相等不跳,之后会补上的
        u=fa[u][i]; v=fa[v][i];
    }
    return fa[u][0]; //由于只会跳到LCA前一个,所以要再取一个父亲
}

over

posted @ 2024-10-11 21:48  EcapsXD  阅读(22)  评论(0)    收藏  举报