[总结]最近公共祖先(倍增求LCA)】的更多相关文章

目录 一.定义 二.LCA的实现流程 1. 预处理 2. 计算LCA 三.例题 例1:P3379 [模板]最近公共祖先(LCA) 四.树上差分 1. 边差分 2. 点差分 3. 例题 一.定义 给定一颗有根树,若节点z既是节点x的祖先,也是节点y的祖先,则称z是x,y的公共祖先.在x,y的祖先中,深度最大的一个节点称为x,y的最近公共祖先(Least Common Ancestors),记做LCA. 如图:LCA(5,7)=2:LCA(3,8)=1:LCA(6,10)=6. 二.LCA的实现流程…
倍增求\(LCA\) 倍增基础 从字面意思理解,倍增就是"成倍增长". 一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\)的区间值.在这些预处理结果的基础上,我们可以进一步求出任意长度区间的答案. 比如区间最值问题\((RMQ)\)就可以使用倍增解决.对于每个起始点,预处理长度为\(2^n\)的区间最值.之后每段区间都可以以此求出,如: \(f(1,7)=\max(f(1,4),f(3,7))\) 以上是最简单的一个举例.在计…
前几天做faebdc学长出的模拟题,第三题最后要倍增来优化,在学长的讲解下,尝试的学习和编了一下倍增求LCA(我能说我其他方法也大会吗?..) 倍增求LCA: father[i][j]表示节点i往上跳2^j次后的节点 可以转移为 father[i][j]=father[father[i][j-1]][j-1] (此处注意循环时先循环j,再循环i) 然后dfs求出各个点的深度depth 整体思路: 先比较两个点的深度,如果深度不同,先让深的点往上跳,浅的先不动,等两个点深度一样时,if 相同 直接…
最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解法. 首先是LCA的倍增算法.算法主体是依靠首先对整个树的预处理DFS,用来预处理出每个点的直接父节点,同时可以处理出每个点的深度和与根节点的距离,然后利用类似RMQ的思想处理出每个点的 2 的幂次的祖先节点,这就可以用 nlogn 的时间完成整个预处理的工作.然后每一次求两个点的LCA时只要对两个…
LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4)一个点地一个点地往上跳,直到到某个点(3)和另外那个点(5)的深度一样 然后两个点一起一个点地一个点地往上跳,直到到某个点(就是最近公共祖先)两个点“变”成了一个点 不过有没有发现一个点地一个点地跳很浪费时间? 如果一下子跳到目标点内存又可能不支持,相对来说倍增的性价比算是很高的 倍增的话就是一次…
1,什么是LCA LCA.最近公共祖先.是一个在解决树上问题最强劲有力的一个工具.一般都是指.在一棵树上取两个节点a,b .另一个节点x它满足  x是a与b的祖先而且x深度最大.这个x就是节点a,b的最近公共祖先. 2,什么是树上倍增. 树上倍增.其实就是通过二进制拆分.将规则一定情况下加速区间状态转移,的一种奇技淫巧.实质是根据已经得到的信息,将考虑的范围扩大一倍,从而加速操作的思想.       其实就是预处理出一个表.每次通过翻倍区间去查询. >往下看<可能会更清楚.毕竟实践是检验真理的…
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4…
LCA也是很经典的内容了,我这个蒟蒻居然今天才开始弄QAQ 我太弱啦! 照例先上定义——————转自维基百科 在图论和计算机科学中,最近公共祖先是指在一个树或者有向无环图中同时拥有v和w作为后代的最深的节点.在这里,我们定义一个节点也是其自己的后代,因此如果v是w的后代,那么w就是v和w的最近公共祖先. 最近公共祖先是两个节点所有公共祖先中离根节点最远的,计算最近公共祖先和根节点的长度往往是有用的.比如为了计算树中两个节点v和w之间的距离,可以使用以下方法:分别计算由v到根节点和w到根节点的距离…
倍增求LCA LCA函数返回(u,v)两点的最近公共祖先 #include <bits/stdc++.h> using namespace std; *; struct node { int v,val,next; node(){} node(int vv,int va,int nn):v(vv),val(va),next(nn){} }E[N]; int n,m; ],dep[N]; void init() { tot = ; memset(head,,sizeof(head)); mems…
洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵树中的n-1条边为“树边” 其他m-n+1条边为“非树边” 枚举每条非树边(x,y,z)添加到最小生成树中 可以在x,y之间构成一个环 设x,y之间的路径最大值为val1 次大值为val2(val1>val2) 则有以下两种情况 当z>val1时 则把val1对应的边换成(x,y,z) 得到一个候…
树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(LCA\) 理解较为简单的一种方法,但速度略慢 倍增是啥? 每个数字都可以拆成几个二的整数次的和,我们可以找出每个数字是由哪几个二的整数次的数合成的 比如说\(14 _ {10} = 1110_2 = 1000 _2 + 100 _2 + 10 _2 = 8 _ {10} + 4 _{10} + 2…
倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. 关于倍增思想: 倍增的思想很简单:通过区间[1,2i-1]与[1+2i-1,2i(2i-1+2i-1)]求出区间[1,2i]. 所以它可以用于区间求最值,求和.而到了树上之后,就变成了,求它往上任意次的祖先. 而倍增求LCA,就是用到了倍增这个功能. 倍增求LCA算法思路: f[i,j],表示结点i…
倍增求lca模板 https://www.luogu.org/problem/show?pid=3379 #include<cstdio> #include<iostream> #include<cmath> #include<cstring> using namespace std; int t,n,cnt,m; int x,y; ][],p,root; ]; ]; ]; ; struct node { int next,to; }e[*]; inline…
题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板(最好采用第一种,第二种纯粹是习惯) #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll…
P3379 [模板]最近公共祖先(LCA) 题目描述: 读入一棵以1为根的树,q次询问,每次给定x和y,问x和y的最近公共祖先是哪一个节点. 树的读入格式:n-1行每行两个整数x.y,表示一条连接x和y的边,保证输入的图形成一棵树. 输入格式: 第一行两个整数为n和q,之后按题目描述读入一棵树. 再之后q行,每行两个整数x和y,表示一组询问. 输出格式: q行,每行1个整数表示答案. 样例输入1: 10 5 2 1 2 3 2 4 5 4 3 6 7 6 8 1 1 9 1 10 9 8 3 1…
pa[a][j] 表示 a 结点的 2^j倍祖先(j = 0时 为直接父亲,j = 1时为父亲的父亲……) 1.首先预处理出所有结点的深度值dep和父亲结点 void dfs(int u, int f, int d) { dep[u] = d; pa[u][] = f; ; i < G2[u].size(); i++) { edge& e = E[G2[u][i]]; int v = e.u == u ? e.v : e.u; if(v != f) { dfs(v, u, d+); } }…
先暂时把模板写出来,A几道题再来补充 此模板也是洛谷上的一道模板题 P3379 [模板]最近公共祖先(LCA) #pragma GCC optimize(2) //o2优化 #include <bits/stdc++.h> using namespace std; typedef long long ll; ;//2的指数的大小 ; int N,M,S; ll bit[L]; int depth[NN];//depth[i]:节点i在树上的深度 int fa[NN][L]; //fa[i][j…
2450. 距离 ★★   输入文件:distance.in   输出文件:distance.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 在一个村子里有N个房子,一些双向的路连接着他们.人们总喜欢问这个“如果1想从房子A走到房子B有多远?”这个通常很难回答.但幸运的是在这个村里答案总是唯一的,自从道路修建以来这只有唯一的一条路(意思是你不能去一个地方两次)在每两座房子之间.你的工作是回答所有好奇的人. [输入格式] 输入文件第一行有两个数n(2≤n≤10000…
先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你不会吧:unamused:...) 思想 树上倍增嘛,顾名思义就是倍增 相信倍增大家都不默认,著名的rmq问题的$O(n*logn)$的解法就是利用倍增实现的 在树上倍增中,我们用 $f[j][i]$表示第$j$号节点,跳了$2^j$步所能到达的节点 $deep[i]$表示$i$号节点的深度 然后用…
思路 运用树上倍增法可以高效率地求出两点x,y的公共祖先LCA 我们设f[x][k]表示x的2k辈祖先 f[x][0]为x的父节点 因为从x向根节点走2k 可以看成从x走2k-1步 再走2k-1步 所以对于1≤k≤logn 有f[x][k]=f[f[x][k-1]][k-1] (类似二分思想) 预处理: 因此我们可以对树进行遍历后得到所有f[x][0] 再计算出f数组的所有值 求LCA: 设dep[x]为x的深度 设dep[x]≥dep[y](否则 可以交换x和y) 使用二进制拆分 把x和y调整…
定义LCA,最近公共祖先,是指一棵树上两个节点的深度最大的公共祖先.也可以理解为两个节点之间的路径上深度最小的点.我们这里用了倍增的方法求了LCA.我们的基本的思路就是,用dfs遍历求出所有点的深度.f[i][j]数组用来求的是距离节点i,距离2^j的祖先.可以知道,f[i][0]就是它的直接父亲.然后通过倍增的思路求出father数组的所有元素.然后进行lca.求lca的基本思路是:先让深度较大的点向上跳,然后x和y再同时向上跳2的幂,总会跳到这样两个点,他们的父亲结点是同一个点,那就是x和y…
LCA(least common ancestors)最近公共祖先 指的就是对于一棵有根树,若结点z既是x的祖先,也是y的祖先(不要告诉我你不知道什么是祖先),那么z就是结点x和y的最近公共祖先. 定义到此. 那么怎么求LCA? 对于朴素思想,就是我要一步一步往上爬..一步一步走.先把结点x和y整到同一深度,然后再一次一个深度的往上查,直到祖先一样才break(明显是个while) 但是,一步一步实在是太慢了,所以不能脚踏实地地走 那么,考虑跳着走, 跳着走的条件就是要满足一步步数尽可能多并且不…
/* 节点维护的信息多样 如果用树状数组维护到根节点的边权或者点权, 可以直接插入点权和边权值,不需要预处理, 但是记得一定要使用ot[]消除影响.即差分. Housewife Wind 这个坑踩得死死得. 然后如果带修改,也可以线段树维护. 打上dfs序后, 其他的就是区间问题了. 然后查询 修改的时候,把dfs序与点或者边对应转换一下就OK了. */ int deep[maxn]; ]; int in[maxn]; // dfs序 入 int ot[maxn]; // dfs序 出 int…
http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点的第2^j个祖先是哪个点,dp[i][0] = i的第一个祖先 = fa[i].转移方程:dp[i][j] = dp[dp[i][j-1][j-1]. #include <cstdio> #include <cstring> #include <algorithm> #in…
算法介绍: 看到lca问题(不知道lca是什么自(bang)行(ni)百度),不难想到暴力的方法: 先把两点处理到同一深度,再让两点一个一个祖先往上找,直到找到一个相同的祖先: 这么暴力的话,时间复杂度基本上是$ o(n) $: 而观察一下暴力的过程,就会发现,其实一个一个祖先往上找效率非常的低,有没有能优化这一过程的方法呢?这时,强大的倍增就出现了,能够把暴力优化到$ o(log(n)) $: 倍增,简单说就是把一步一步跳替换成每次跳$ 2^i $个祖先: 做法: 先预处理出每个点的深度(df…
题面 传送门 题目大意: 给定一个无向连通带权图G,对于每条边(u,v,w)" role="presentation" style="position: relative;">(u,v,w)(u,v,w),求包含这条边的生成树大小的最小值 分析 包含这条边的生成树的大小如何表示呢? 先求出整张图的最小生成树大小tlen,对于每一条边(u,v,w)" role="presentation" style="posi…
2019-11-07 09:25:45 C.树之呼吸-叁之型-树上两点路径长度 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 7 (4 users) Total Accepted: 2 (2 users) Special Judge: No Description 给一棵 n 个结点的树,结点编号从 1 到 n,并指定 m 号结点为根: 给出 q 个询问,每次询问从编号为 x 的结点到编号为 y 的结点的路径长度. Input 输…
1.tarjan求lca 思想: void tarjan(int u,int f){ for(int i=---){//枚举边 if(v==f) continue; dfs(v); //继续搜 unionn(v);//合并 vis[v]=; //标记 } for(int i){// 和u有关的询问 if(vis[v]) lca=find(v); //若访问过,lca为find(v) } } 模板代码 #include<bits/stdc++.h> #define rep(i,x,y) for(…
描述 上上回说到,小Hi和小Ho用非常拙劣--或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的--这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是购买更为昂贵的服务器,通过提高计算机性能的方式来满足需求--但小Hi和小Ho并没有那么多的钱:其二则是改进他们的算法…
传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是…