【c++提高1】最近共先祖LCA优化求法

大纲

1.树上倍增&欧拉序+RMQ
2.Tarjan
3.例题

1.树上倍&欧拉序+RMQ

定义:给定一棵有根树,若节点u既是节点x的祖先,也是节点y的祖先,则称u是x和y的公共祖先。
在x,y的所有公共祖先中,深度最大的一个称为x,y的最近公共祖先,记为LCA(x, y)。
例如:下图中,2和3的最近公共祖先是1, 2和5的公共祖先是2。4和9的最近公共祖先是2。
在这里插入图片描述两个结点的公共祖先可能有多个(例如2和1都是4,5的公共祖先),但最近公共祖先只有一个。

向上标记:
① 从x向上遍历,直到根节点,遍历过程中标记所有x的祖先。
② 从y向上遍历,遍历过程中首次遇到已标记结点时,该节点就是LCA(x, y);
向上标记法单次询问时间复杂度为:O(N)。
朴素算法:
① DFS/BFS求出树中每个节点的深度。
② 将x和y中深度较大的向上调整,直到x和y的深度相同。
③ 将x和y同时向上调整,直到相遇,首次相遇的结点即是x和y的最近公共祖先。
朴素算法单次询问时间复杂度为:O(N)。
在朴素算法中x和y向上调整时都是一步一步向上调整,倍增法使用倍增的方式向上调整。
在将x和y以倍增的方式向上调整时,如何知道倍增后的祖先是谁?
定义p[i][j]表示节点i的2^j祖先,倍增过程中通过p数组直接获取倍增后的祖先。
如何预处理p[i][j]的值?
i的2 ^ j祖先是i的2 ^ (j-1)祖先的2(j-1)祖先,即:p[i][j] = p[p[i][j-1]][j-1];
可以在dfs/bfs计算结点深度的同时初始化p数组,因为无论是dfs还是bfs都是
从根节点出发,当搜索到节点x时,其所有祖先一定都搜索过了。
预处理p数组时间复杂度为:O(Nlog(N))。
① DFS/BFS求出树中每个节点的深度,并预处理除任意节点的2 ^ j祖先,即: p数组。
② 将x和y中深度较大的以倍增的方式向上调整,直到x和y的深度相同。

if (d[x] < d[y])
	swap (x , y) ;
for (int j = log2n; j >= 0; j --)
	if (d
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

{∞}

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值