最近公共祖先(LCA)
倍增求LCA
用 \(f_{x,k}\) 表示 \(x\) 向根节点走了 \(2^k\) 步到达的节点。
易得:
\[f_{x,k+1}=f_{f_{x,k},k}
\]
所以遍历一次图可预处理出。
对于一组 \((x,y)\) 的询问:
- 选择深度更深的节点,倍增跳到与另一点深度相同处。
- 若此时两点相同,则得出答案。
- 否则 \(x,y\) 在不重合的前提下一只向上倍增。
- 最后 \(x\) 或 \(y\) 的父亲一定是 LCA。
inline void bfs(){
t=(int)log(n)/log(2)+1;
q.push(root);d[1]=1;
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(d[y])continue;
d[y]=d[x]+1,f[y][x]=0,q.push(y);
for(int j=1;j<=t;j++)f[y][j]=f[f[y][j-1]][j-1];
q.push(y);
}
}
}
inline int Lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=t;i>=0;i--)
if(dep[f[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=t;i>=0;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
P4180 [BJWC2010]严格次小生成树
容易得到,严格次小生成树一定是最小生成树替换一条边得到的。
先求出最小生成树,考虑加入未在最小生成树内的边 \((x,y,z)\),那么树上 \(x\) 到 \(y\) 的路径上一定有一条边被替换。
令 \(x\) 到 \(y\) 的路径上最小边权为 \(z_1\),严格次小边权为 \(z_2\), 那么:
- 当 \(z\ne z_1\) 时,替换 \((x,y,z)\) 得到的严格次小生成树一定换去 \(z_1\) 这条边。
- 否则换去 \(z_2\) 这条边。
用树上倍增求出 \(z_1\),\(z_2\),此过程和求 LCA 相似。
P4281 [AHOI2008]紧急集合 / 聚会
建议画图理解。
引理1:三个点的两两 LCA 必有一对重合。
反证法易证。
引理2:答案一定是另一个 LCA。
如果选另一个LCA,两个 LCA 中间的边被经过1次,否则被经过2次。
由于一种状态想要缩小只有一种方案,所以可以把缩小的方案建成一棵树,答案就是起始和结束状态的 LCA。
考虑不暴力缩小,而是一次把一边缩小到比另一边小。
最后二分距离 LCA 的距离后倍增即可。

浙公网安备 33010602011771号