【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

浙公网安备 33010602011771号