求解lca问题

文章目录

倍增法

一篇博客
最常用,也是最简单的算法,实质就是直接对暴力使用倍增优化将复杂度降低达到需求。
d e p t h [ ] depth[] depth[]为每个节点的深度, f a [ i ] [ j ] fa[i][j] fa[i][j],i节点的 2 j 2^j 2j的父亲。 l g [ i ] = l o g 2 i + 1 lg[i]=log_2{i}+1 lg[i]=log2i+1

const int maxn=5000001;
int depth[maxn],fa[maxn][22],lg[maxn];
vector<int >g[maxn];
void dfs(int now,int fath)//dfs初始化fa和depth,传入参数为根节点
{
   
   
	fa[now][0]=fath;
	depth[now]=depth[fath]+1;
	for(int i=1;i<=lg[depth[now]];++i)
	{
   
   
		fa[now][i]=fa[fa[now][i-1]][i-1];//递推更新fa
	}
	for(int i=0;i<g[now].size();i++)//寻找子节点
	{
   
   
		if(g[now][i]!=fath)
		dfs(g[now][i],now);
	}
}
int lca(int x,int y)
{
   
   
	if(depth[x]<depth[y])//使x的深度大于y的深度
	{
   
   
		swap(x,y);
	}
	while(depth[x]>depth[y])
	{
   
   
		x=fa[x][lg[depth[x]-depth[y]]-1];//使两者深度相同
	}
	if(x==y)
	return x;
	for(int k=lg[depth[x]]-1;k>=0;--k)//树上倍增
	{
   
   
		if(fa[x][k]!=fa[y][k])
		{
   
   
			x=fa[x][k],y=fa[y][k];
		}
	}
	return fa[x][0];
}
main(void)
{
   
   
	int n,m,s;
	cin>>n>>m>>s;
	for(int i=1;i<n;i++)
	{
   
   
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x); 
	}
	for(int i=1;i<=n;i++)
	{
   
   
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	}
	dfs(s,0);
	for(int i=1;i<=m;i++)
	{
   
   
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d\n",lca(x,y));	
	}
	return 0;
}

题目

二叉树问题
统计树的深度、宽度、两个点之间的上行边数和下行边数

const int maxn=5000001;
int depth[maxn
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值