LCA_倍增

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);






猜你喜欢

转载自blog.csdn.net/wangyc123456/article/details/80343216