LCA是最近公共祖先
倍增比较好写
查询LCA(x,y)的步骤:
1.如果x比较浅,那就交换
2.将x倍增向上跳到与深度相同的位置
3.1.如果此时x=y,lca为x
3.2.否则,x,y一起跳,具体步骤下面说明
-----------------------------------------------------------
在询问LCA之前,先建树
一般会给出根节点s
用邻接表存无向边,然后从s开始dfs
dfs过程中,计算这个节点的深度depth,和f[i][j],表示从这个节点i向上跳2^j到哪个节点,是递推得的,
具体下面说明
-----------------------------------------------------------
先是dfs的代码附说明
void dfs(int u,int fa) //两个参数,本节点u及父亲节点fa,父亲节点的作用是计算u深度 { depth[u]=depth[fa]+1; //深度 f[u][0]=fa; //表示向上跳一格到了父亲 for (register int i=1;(1<<i)<=depth[u];i++) //计算f值 f[u][i]=f[f[u][i-1]][i-1]; //计算f[u][i]时,f[u][i-1]一定已经计算过,因为深度肯定比较浅 for (register int i=head[u];i;i=e[i].nex) //继续深搜 { int v=e[i].to; if (v!=fa) dfs(v,u); } }
然后是LCA的代码附说明
int LCA(int x,int y) //求x,y得最近公共祖先,有返回值 { if (depth[x]<depth[y]) swap(x,y); //调整使x比较深,然后从x向上跳 while (depth[x]>depth[y]) //只要比y深就执行,while写起来比较方便 x=f[x][lg2[depth[x]-depth[y]]]; //lg2[i]表示log2,i的下界值,倍增的思想,若干不同的2^k可以组成任意整数,优先大的2^k if (x==y) return x; //在同一点,返回值 for (register int i=lg2[depth[x]];i>=0;i--) //倍增思想,重点,i的初始值<=深度 { if (f[x][i]!=f[y][i]) //假如相同,一定是跳过头/或刚好是lca,就算会跳到树根外也没关系,此时f值也相同,为0 //特别是刚好lca吔没关系,因为接下来的i也一定能组成 x=f[x][i],y=f[y][i]; //向上跳 } return f[x][0]; //这时父亲就是lca }
最后是lg2的递推
for (register int i=1;i<=n;i++) lg2[i]=lg2[i-1]+(1<<(lg2[i-1]+1)==i);