Loading

【笔记】最近公共祖先 - 欧拉序

一个 \(O(n\log n)\) 预处理,\(O(1)\) 求 LCA 的科技。

欧拉序

图来自 Luogu @Rainbow_qwq

欧拉序即为 DFS 序中添加回溯经过的节点。

此树的欧拉序为 \(1→2→4→7→4→8→4→2→5→2→1→3→6→3→1\)

欧拉序求 LCA

欧拉序的性质:两个节点第一次出现的位置间包含两点间路径上的点和他们子树里的点。

也就是说,我们找到这个区间中深度最小的点,就是这两个点的 LCA。

区间静态最值使用 ST 表即可做到 \(O(n\log n)\) 预处理,\(O(1)\) 查询。

因为 ST 表常数较大,所以有时并没有树剖跑得快。

实现

DFS 预处理欧拉序:

int dfn[2*N],que[2*N],idx;
void dfs(int u,int fa){
    dfn[u]=++idx,que[idx]=u;
    dep[u]=dep[fa]+1;
    for(int i=h[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u);
        que[++idx]=u;
    }
}

预处理 ST 表:

void st(){
    for(int i=1;i<=idx;i++) f[i][0]=que[i];
    for(int j=1;j<=20;j++){
        for(int i=1;i+(1<<j)<=idx;++i){
            int f1=f[i][j-1],f2=f[i+(1<<j-1)][j-1];
            if(dep[f1]<dep[f2]) f[i][j]=f1;
            else f[i][j]=f2;
        }
    }
}

查询:

int LCA(int a,int b){
    if(dfn[a]>dfn[b])swap(a,b);
    a=dfn[a],b=dfn[b];
    int len=lg[b-a+1],f1=f[u][len],f2=f[v-(1<<len)+1][len];
    if(dep[f1]<dep[f2]) return f1;
    else return f2;
}
posted @ 2026-01-09 20:57  Seqfrel  阅读(37)  评论(0)    收藏  举报