对倍增求LCA的理解


\(updata : 2021.11.22\) 复习 \(LCA\) , 才发现对 \(LCA\) 并不理解.


\(① :\) \(倍增数组的构建\)

易想到 : bz[i][j] = bz[bz[i][j-1]][j-1] .

那枚举顺序呢? 我复习时想到的是先枚举点 \(i\) , 在枚举到 \(2\) 的倍数 \(j\) , 这样 bz[i][j-1] 必然是 \(i\) 的祖先 , 那么考虑到 \(DP\) 更新顺序 , 可以考虑 \(dfs\) 遍历顺序更新.

void dfs1(int x,int f){
	for(int k=head[x];k;k=len[k].next){
		int to = len[k].to;
		if(to != f){
			for(int j=1;j<=19;++j)
				bz[to][j] = bz[bz[to][j-1]][j-1];
			dfs1(to , x);
		}
	}
}

看了一下 \(std\) , 发现先枚举 \(j\) , 再枚举 \(i\) 即可.

for(int j=1;j<=19;++j)
		for(int i=1;i<=n;++i)
			bz[i][j] = bz[bz[i][j-1]][j-1];

\(② :\) 倍增跳到相同的高度

先看代码:

	for(int j=19;j>=0;--j)
			if(dep[ bz[x][j] ] >= dep[y])
				x = bz[x][j];

包括后面的倍增跳 \(LCA\) , 我都认为了都利用了"数的二进制拆分"的思想 , 有如下子问题:

"如何将 t 二进制数的各位位置找出来?"

其实我们从 \(2^n\) ( \(n\) 是一个足够的数 , \(2^n > t\) ) , \(n\)自减 , \(t\) 能减 \(2^n\) 就减 , 此时 \(n\) 必是一个位置.

注意一定是高位从低位枚举 , 而不是从低位枚举到高位.

同理就会明白倍增数组为什么从高位枚举.

\(③ :\) 倍增跳 \(LCA\) , 同理 \(②\) .

\(④ :\) 为什么是答案是 \(fa[x]\)

举个例子 : 如果二者的 \(2^n\) 辈相同时( \(LCA\) ) , 并不赋值 x = bz[x][n] , 而将 \(2^n\) 再二进制拆解 , 最后 \(2^n\) 不断变小 , \(n\) 必最后为 \(0\) .为什么不发现 \(LCA\) 就直接停止呢? 因为 \(n\) 从高位枚举 , 到 \(LCA\) 之前的 \(2^n\) 辈都相同 , 怎么会知道哪点是 \(LCA\) , 所以有 while(bz[x][j] != bz[y][j]) x = bz[x][j] , y = bz[y][j]; ,只有不等才改.

相关