倍增求LCA(240822)

介绍:LCA为最近公共祖先,表示离两个点最近的公共祖先

解法:从两个点中的一个往上跳:

第一次跳$2^0$

第二次跳$2^1$

第三次跳$2^2$......

这样就可以$O(logN)$解决问题



代码实现:

先求每个点深度,并记录父亲

void dfs1(ll x,ll sc){
	faa[x]=sc;//深度
	vis[x]=1;
	for(int i=head[x];i;i=es[i].nxt){
		ll v=es[i].v;
		if(!vis[v]){
			fa[v][0]=x;
			dfs1(v,sc+1);
		}
	}
}

再算出第\(2^i\)个父亲是谁

for(int i=1;i<=17;i++){
	for(int j=1;j<=n;j++){
		fa[j][i]=fa[fa[j][i-1]][i-1];
		//这里要理解,假设i=2,那求出的就是j点的第2^(i-1)个父亲的第2^(i-1)个父亲
		//也就是4,满足2^2=4
	}
}

最后再往上跳

ll lca(ll x,ll y){
	if(faa[x]<faa[y]){//y深度要小
		swap(x,y);
	}
	for(int i=17;i>=0;i--){//把x往上跳,尽量跳到与y同一层
		if(faa[fa[x][i]]>=faa[y]){
			x=fa[x][i];
		}
	}
	if(x==y){
		return x;
	}
	for(int i=17;i>=0;i--){
		if(fa[x][i]!=fa[y][i]){//不可以等于,要跳到LCA的下面一层
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];//上面一层即为答案
}
posted @ 2024-10-05 22:23  MistyPost  阅读(21)  评论(0)    收藏  举报