LCA学习

今天学习了一发LCA算法

所谓LCA,就是最近公共祖先,lowest common ancestor

有O(n)的朴素算法,详见挑战程序设计竞赛 328页

LCA一般有两种解法,都是O(logn)复杂度的

1.基于二分搜索的算法

2.基于RMQ的算法

这些都是书上有的

所以用一个题目来解释把

POJ 2763

这题说实话还是有点难度的,因为找LCA的时候还要计算边权和,用二分搜索(倍增法)的时候可以记录边权和,但是还要修改边权,这样的话倍增法就非常难以快速修改

所以这题要用基于RMQ的LCA算法,首先RMQ算法的编号数量是节点个数*2-1,BIT的节点个数也是这些,所以就可以用一个时间戳k搞定

首先你要求a-b的距离,那么就是dis[a]+dis[b]-2*dis[lca(a,b)]

dis是这个节点到root的距离,这个公式是很好理解的

求lca用RMQ的方法,只要求id[a]和id[b]之间depth最小的编号i就行,然后vs[i]就是节点

主要这个修改是亮点,区间修改一般都是用线段树来维护的,但是这题线段树太复杂了,反正我不会

听说树链剖分可以解决这种问题,我也不懂,于是就看题解用的BIT(树状数组)

因为RMQ把每个节点走的顺序都列出来了,所以如果修改的是edge[a][b],fa[b]==a的话,只要修改b以及b为根下面的子树到根节点的距离,所以要开个边数组记录每条边的端点和权值,然后做修改

b以及b以下的节点,在RMQ的那个列表中,就是第一个b出现的编号和最后一个b出现的编号之间的那个区间,并且树状数组i不能从0开始,所以编号要+1。

最后一个b出现的编号应该记录最后b出现的位置+1的编号

因为要从第一个b开始用树状数组增加修改多出来的值,然后从最后个b的后一位开始减去增加的值,(如果从最后个b开始的话,那么a-b这条边也被减去了)

题目还是有点复杂的,毕竟初学,但是收获颇大

AC代码地址:http://paste.ubuntu.net/12304944/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值