【算法】RMQ LCA 讲课杂记
4月4日,应学弟要求去了次学校给小同学们讲了一堂课,其实讲的挺内容挺杂的,但是目的是引出LCA算法。
现在整理一下当天讲课的主要内容:
开始并没有直接引出LCA问题,而是讲了RMQ(Range Minimum/Maximum Query)问题。
RMQ指的是对于给定的一个数组,每一次询问一个区间[L,R]中数字的最小或最大值,一个很经典的问题。
一开始没有学生知道如何求解此问题。我将问题弱化,每一次询问[1,R]中数字的最值,有学生打出了求一个min/max数组即可,此为正解。
这是一个相当正确的做法,有许多学过线段树的同学在碰到这个弱化的问题时也会不假思索的无脑线段树,将简单的问题复杂化。学生能直接答出min/max数组,我认为也是因为他们现在会的算法还太少,基本没有干扰项。
我接下来介绍了ST表(Sparse Table)求解RMQ。
如果我们现在有一个二维数组f[i][j]表示从第i个数开始包括自己向后总共2^j个数字中的最值,如何求解RMQ?
底下有学生给了一种我觉得挺不错的思路:求出L与R的范围D,将D作二进制分解,则可以在log(D)的复杂度呢,通过若干个f数组中的值求解得出L与R之间数字的最值。
这个思路相当nice,但是我说,其实还是不够优秀,因为事实上只要至多2个数字便可以得出结果了。
如果D是一个2的幂,则只f[L][log2(D)]直接就是答案,否则答案为min/max(f[L][(int)log2(D)][R-2^((int)log2(D))+1][(int)log2(D)]),看上去有些复杂,其实写在代码中比较方便,含义就是求出最大的k使得2^k小于D,接着用左边和右边2段的f值一定能完整覆盖到整个范围区间。
实际上,上述两种情况可以归一化为第二种计算方式。
接下来的问题就是如何求解f数组。其实ST表本质上是一种动态规划的思想,首先初始化所有的f[i][0]为a[i],也即原来的值,接下去从1开始向上循环,直到超过log(n)。f[i][j]=min/max(f[i][j-1],f[i+2^(j-1)][j-1])
至此ST表算法讲授完毕。另外一点想提的是,很多人会把RMQ等同于ST表,这是一种误会。RMQ并不是一种算法,是区间最值问题,本质上是一类问题。RMQ当然也可以用线段树解决。甚至brute force也可以称为RMQ的一种算法。
接下去,我讲了有向图深度优先遍历中的四类边,本文不作展开。
最后,我引出了LCA问题。底下的学生没有人知道不用暴力怎么做。但是有的学生的暴力思路还是有些interesting的,例如先遍历一遍树,当发现第一个点后,在回溯时,标记走过的点的值+1,。再遍历一次树,当发现第二个点后,在回溯时,标记走过的点的值+1,第一次发现有个点值为2,则说明是两个点的最近公共祖先。
我觉得这个思路还是有点意思的,因为比较反常规。
我主要讲了三种求解LCA问题的算法。
第一种是将其归约至RMQ问题。如何规约呢?在遍历到一个节点与回溯到一个节点时,打时间戳,并记录这个时间戳对应的节点。则LCA问题可以规约为对应2个点第一次被遍历到的时间戳之间所有所有时间戳,哪个时间戳对应的节点的深度最小。
听起来有些复杂,其实想想就是那么回事情。
在问到如何将LCA规约至RMQ时,有一个学生意外地联想到了第二种方法,不过他没有完整地想出来。
第二种算法叫树上倍增,与ST表有异曲同工之处,f[i][j]表示节点i的第2^j个祖先。
则求解LCA的算法流程大致是这样的,两个点u和v,不妨假设u的深度大于等于v的深度,则让u向上到两点处于同一个深度。如果两个点相同,则直接返回答案。否则从大到小枚举2的幂,看是否两个点向上那么多个祖先是相同的,如果相同,则认为走过头了,continue掉。否则将其置为新的祖先点。最后2个点再向上走一次,也即他们的父亲节点就是LCA。这其中让u向上走到与v相同高度,用的方法与上文RMQ问题中学生提到的二进制分解是一个思路,即将深度差作二进制分解,向上跳log(d)次。
第三种算法是Tarjan发明的一种基于并查集的离线算法。
所谓离线即先一次性将所有的询问保存,对树做深度优先遍历,每一次遍历完之后,将子树对应的集合合并至当前节点。递归完所有子节点后,遍历所有与当前点相关的询问,如果另外一个点已经被访问过了,则这个询问的答案为另一个点所在集合的代表元。
最后我当时提了一下,没有深入讲,是用树链剖分求解LCA问题。有点杀鸡用宰牛刀的感觉了。
【算法】RMQ LCA 讲课杂记的更多相关文章
- poj3728之离线LCA+dp思想/RMQ+LCA(非常好的题目)
题意很简单 给一个树(n < 5w) 每个点有个权值,代表商品价格 若干个询问(5w) 对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品, ...
- tarjan算法求LCA
tarjan算法求LCA LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先. 这里我们使用tarjan算法离线算法解决这个问题. 离线 ...
- 【37.48%】【hdu 2587】How far away ?(3篇文章,3种做法,LCA之ST算法(RMQ))
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...
- 【图论算法】LCA最近公共祖先问题
LCA模板题https://www.luogu.com.cn/problem/P3379题意理解 对于有根树T的两个结点u.v,最近公共祖先LCA(u,v)表示一个结点x,满足x是u.v的祖先且x的深 ...
- dfs序 + RMQ = LCA
dfs序是指你用dfs遍历一棵树时,每个节点会按照遍历到的先后顺序得到一个序号.然后你用这些序号,可以把整个遍历过程表示出来. 如上图所示,则整个遍历过程为1 2 3 2 4 5 4 6 4 2 1 ...
- poj 1330(RMQ&LCA入门题)
传送门:Problem 1330 https://www.cnblogs.com/violet-acmer/p/9686774.html 参考资料: http://dongxicheng.org/st ...
- 算法笔记--lca倍增算法
算法笔记 模板: vector<int>g[N]; vector<int>edge[N]; ][N]; int deep[N]; int h[N]; void dfs(int ...
- hdu 2874 Connections between cities(st&rmq LCA)
Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
- hihoCoder#1067(离线算法求LCA)
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中 ...
随机推荐
- js实现Mac触摸板双指事件(上、下、左、右、放大、缩小)
前言 这几天在修复一个web问题时,需要捕获Mac触摸板双指事件(上.下.左.右.放大.缩小),但发现并没有现成的轮子,还是要自己造. 例如:jquery.mousewheel.js(添加跨浏览器的鼠 ...
- 南京.NET技术行业落地分享交流会圆满成功
3月11日,由南京.NET社区发起,纳龙科技赞助,并联合举办的,.NET技术线下交流活动,圆满成功. 这是南京.NET圈子第一次的小型聚会,为了办好此次活动,工作人员不敢怠慢.早早准备好了小奖品与水果 ...
- 算法模板——平衡树Treap 2
实现功能:同平衡树Treap 1(BZOJ3224 / tyvj1728) 这次的模板有了不少的改进,显然更加美观了,几乎每个部分都有了不少简化,尤其是删除部分,这个参照了hzwer神犇的写法,在此鸣 ...
- tp框架之对列表的一系列操作及跳转页面(详细步骤)
依旧是在Main控制器里面写类方法,如果想看tp全部的话,可以从前几篇开始看,都是一整个步骤下来的 在控制器中重新写个类 然后再做个shouye.html页面 nation表的数据,将会在shou.h ...
- Internet Information Services安装与启动
Internet Information Services安装 1.打开控制面板——程序——启动或关闭windows功能 2.找到Internet Information Services ——将其全 ...
- C++STL的简单使用
#include <iostream>#include <vector>#include<deque>#include <list>#include&l ...
- Visual Studio 2017 新特性
全新的安装体检 VS2017更好的支持了按需安装的特点,用户可以仅选择需要的功能安装,节省了不少的Disk 最小的安装仅有几百兆,但也支持20多种编程语言的编辑和源码管理 支持创建自定义的离线安装包 ...
- js中关于string的一些常用的方法
最近总结了一些关于string中的常用方法, 其中大部分的方法来自于<JavaScript框架设计>这本书, 如果有更好的方法,或者有关于string的别的常用的方法,希望大家不吝赐教. ...
- vue2.0自定义指令的使用方法
感觉2.0好坑啊,自定义指令和1.0完全不一样,并且文档写得也不太清晰,下面是我写得一个demo,希望帮助大家更好地理解自定义指令 <!DOCTYPE html> <html lan ...
- PRINCE2学习
今天对PRINCE2中提及的7大主题进行学习,主要的内容是通过概述和PMBOK之间的对比做一些总结,每个主题所包含的过程和方法并没有太多涉及,没有对整个体系有全面深入的学习,有些断章取义的地方也请博友 ...