LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4)一个点地一个点地往上跳,直到到某个点(3)和另外那个点(5)的深度一样 然后两个点一起一个点地一个点地往上跳,直到到某个点(就是最近公共祖先)两个点“变”成了一个点 不过有没有发现一个点地一个点地跳很浪费时间? 如果一下子跳到目标点内存又可能不支持,相对来说倍增的性价比算是很高的 倍增的话就是一次…
倍增LCA \(fa[a][i]\)代表a的第\(2^{i}\)个祖先. 主体思路是枚举二进制位,让两个查询节点跳到同一高度然后再向上跳相同高度找LCA. int fa[N][21], dep[N]; void dfs(int u, int f) { dep[u] = dep[f] + 1, fa[u][0] = f; for (int i = 1;i <= 20;i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int i = head[u];i;i…
算法介绍: 看到lca问题(不知道lca是什么自(bang)行(ni)百度),不难想到暴力的方法: 先把两点处理到同一深度,再让两点一个一个祖先往上找,直到找到一个相同的祖先: 这么暴力的话,时间复杂度基本上是$ o(n) $: 而观察一下暴力的过程,就会发现,其实一个一个祖先往上找效率非常的低,有没有能优化这一过程的方法呢?这时,强大的倍增就出现了,能够把暴力优化到$ o(log(n)) $: 倍增,简单说就是把一步一步跳替换成每次跳$ 2^i $个祖先: 做法: 先预处理出每个点的深度(df…
题意: 给你一棵有n个节点的树,给你m次询问,查询给两个点,问树上有多少个点到这两个点的距离是相等的.树上所有边的边权是1. 思路: 很容易想到通过记录dep和找到lca来找到两个点之间的距离,然后分情况讨论. 一开始困扰我的问题是如果lca不是正中间的点,如何在比较低的复杂度的层面上求解中点. 倍增法lca不光可以在logn的时间复杂度内查询某两个点的lca,还可以实现在logm的时间复杂度能查询某个节点的第m个父亲节点. 算法的核心是用二进制的运算来实现查询. #include<bits/s…
POJ3417:http://poj.org/problem?id=3417 思路 我们注意到由“主要边”构成一颗树 “附加边”则是非树边 把一条附加边(x,y)加入树中 会与树上x,y之间构成一个环 因此 我们称每条附加边(x,y)都把树上x,y之间的路径覆盖一次 我们只需要统计出每条“主要边”被覆盖几次 有以下几种情况 第一步把覆盖0次的主要边切断 则第二步可以任意切一条附加边 ans+=m 第一步把覆盖1次的主要边切断 则第二步只有一种选择切附加边 ans+=1 第一步把覆盖2次或以上的主…
[模板·I]LCA(倍增版) 既然是一篇重点在于介绍.分析一个模板的Blog,作者将主要分析其原理,可能会比较无趣……(提供C++模板) 另外,给reader们介绍另外一篇非常不错的Blog(我就是从那篇博客开始自学LCA的):+LCA-by 殇雪+ 一.原理 LCA即最近公共祖先,一般用LCA(u,v)表示u.v的最近公共祖先.举个例子: (Tab:以下“树”均指有根树)由于在树中,除根节点的每个节点都有且仅有一个父节点,我们很容易得到一个结论——u,v的最近公共祖先的任意祖先一定也是u,v的…
倍增求\(LCA\) 倍增基础 从字面意思理解,倍增就是"成倍增长". 一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\)的区间值.在这些预处理结果的基础上,我们可以进一步求出任意长度区间的答案. 比如区间最值问题\((RMQ)\)就可以使用倍增解决.对于每个起始点,预处理长度为\(2^n\)的区间最值.之后每段区间都可以以此求出,如: \(f(1,7)=\max(f(1,4),f(3,7))\) 以上是最简单的一个举例.在计…
倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. 关于倍增思想: 倍增的思想很简单:通过区间[1,2i-1]与[1+2i-1,2i(2i-1+2i-1)]求出区间[1,2i]. 所以它可以用于区间求最值,求和.而到了树上之后,就变成了,求它往上任意次的祖先. 而倍增求LCA,就是用到了倍增这个功能. 倍增求LCA算法思路: f[i,j],表示结点i…
前几天做faebdc学长出的模拟题,第三题最后要倍增来优化,在学长的讲解下,尝试的学习和编了一下倍增求LCA(我能说我其他方法也大会吗?..) 倍增求LCA: father[i][j]表示节点i往上跳2^j次后的节点 可以转移为 father[i][j]=father[father[i][j-1]][j-1] (此处注意循环时先循环j,再循环i) 然后dfs求出各个点的深度depth 整体思路: 先比较两个点的深度,如果深度不同,先让深的点往上跳,浅的先不动,等两个点深度一样时,if 相同 直接…
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4…