最近公共祖先 学习笔记

概念

一棵有根树,求两个点的最近公共祖先。

方法

1. 倍增法:\(O(n)-O(\log n)\)

int lca(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y]) x=fa[x][__lg(dep[x]-dep[y])-1];
	if(x==y) return x;
	for(int k=__lg(dep[x])-1; ~k; k--)
		if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k];
	return fa[x][0];
}

2. dfs 序求 lca:\(O(n\log n)-O(1)\)

int get(int x,int y) {return dfn[x]<dfn[y]?x:y;}
void dfs(int x,int fa) {
    st[dfn[x]=++cnt][0]=fa;
    st[1][1]=fa;
    for(auto y:e[x]) if(y!=fa) dfs(y,x);
}
void build_st() {
    int k=__lg(n);
    for(int i=1; i<=k; i++)
        for(int j=1; j+(1<<i)-1<=n; j++)
            st[j][i]=get(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}
int lca(int x,int y) {
    if(x==y) return x;
    if((x=dfn[x])>(y=dfn[y])) swap(x,y);
    int k=__lg(y-x++);
    return get(st[x][k],st[y-(1<<k)+1][k]);
}

3. 树剖求 lca:\(O(n)-O(\log n)\)

int lca(int x,int y) {
	while(top[x]^top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
posted @ 2024-04-14 10:33  lgh_2009  阅读(3)  评论(0编辑  收藏  举报