关于LCA的倍增解法的笔记】的更多相关文章

emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w 首先 何为LCA? LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主要任务是... LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 怎么样,很好理解吧! 然后,关于倍增 emmmmm,可以这么理解: …… …… …… https://blog.csdn.net/jarjingx/artic…
LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链向上,直至二者在一条链上 tarjan_lca:离线O(n+m) 先记录所有的询问,对树进行一次dfs,对于搜索到的点u,先将点u往下搜,再将点u与父节点所在集合合并,之后对于它的所有询问(u,v),若v已被访问,那么找v所在集合的祖先e,则e就是u与v的lca 但我们今天要讲的是 倍增lca 所谓…
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 5 5 4 3 1 2 4 5…
Luogu P3379 题意:对于两个节点,寻找他们的最近公共祖先. 一个显而易见的解法是对于每一个节点我们都往上遍历一遍,记录下它每一个祖先,然后再从另一个节点出发,一步一步往上走,找到以前记录过第一个节点就是这两个节点的LCA 事实上在这样的数据规模下,这种解法的时间复杂度是让人无法接受的. 很容易发现,这样的解法慢在两个节点是一步一步往上走的,也许可以想个办法一次跳一大步? 于是我们引入了倍增法求LCA. 我们知道,对于任意一个整数数,都可以使用\(2^k+2^{k-1}+...+2^0\…
LCA就是最近公共祖先,比如 节点10和11的LCA就是8,9和3的LCA就是3. 我们这里讲一下用树上倍增来求LCA. 大家都可以写出暴力解法,两个节点依次一步一步往上爬,直到爬到了相同的一个节点. 二树上倍增就是对暴力的优化,改成了一次爬好几步. 具体怎么爬呢?就是两个点每次爬 2^j 步,而 j 满足的是两个点爬到的点不能相同,因为这样可能是公共祖先,但不一定是最近的.在这种条件下要使 j 尽可能的大. 举个例子,比如上图的节点7和8,当 j = 2 时,都爬到了节点 1,然而很显然这不是…
倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ]; void dfs(int x,int fa) { int i,k; vis[x]=; anc[x][]=fa; deep[x]=deep[fa]+; ;i<=log2n;i++) anc[x][i]=anc[anc[x][i-]][i-]; ;k=e[k].next) if(!vis[e[k].…
题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力 输入描述 Input Description 第一行一个n,接下来…
倍增(爬树)算法,刚刚学习的算法.对每一个点的父节点,就记录他的2k的父亲. 题目为http://www.luogu.org/problem/show?pid=3379 第一步先记录每一个节点的深度用一个深搜,顺便对每个节点的20赋初值为自己的上一个节点. 第二步通过第一步的初始化对每个节点的2k次进行赋值为fa[i][j]=fa[ fa[i][j-1] ][ j-1 ];自己的j-1次幂的父节点的i-1次就是就是自己的j次幂. 第三步对询问做出处理 1,先判断x,y的深度,如果x比y浅就换位置…
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow, and Blue are in war. The map of battlefield is a tree, which means that there are N nodes and (N – 1) edges that connect all the nodes. Each country…
转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud E. A and B and Lecture Rooms A and B are preparing themselves for programming contests. The University where A and B study is a set of rooms connected by corridors. Overall, the University ha…
时间复杂度: dfs树,求st表(状态数组f):O(NlgN) 处理M个查询:O(MlgN) 总:O((M+N)lgN) #include<iostream> #include<cstdio> #include<cmath> using namespace std; const int maxn=500010; struct edge{ int t; edge * nxt; edge(int to, edge * next){ t=to, nxt=next; } };…
题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000). 现在有 K个询问 (1 < = K < = 20,000). 每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少? 输入 第一行: N, M, K. 第2..M+1行: 三个正整数:X, Y, and…
引入: 比如说要找树上任意两个点的路上的最大值.如果是一般的做法 会 接近o(n)的搜,从一个点搜到另一个点,但是如果询问多了复杂度就很高了. 然后我们会预处理.预处理是o(n²)的,询问是o(1)的,但是n大了,时间会超,内存也开不下. 这个时候就需要lca了.如果是倍增lca的话.处理是o(nlogn的),询问是o(logn)的,你发现什么东西都log一遍就很简单了... lca: 先说下lca.为什么要用lca,打个比方,如果我们事先知道了一个点往上任何一个点是啥,并且到它的路径上的最大值…
补了一发LCA,表示这东西表面上好像简单,但是细节真挺多. 我学的是树上倍增,倍增思想很有趣~~(爸爸的爸爸叫奶奶.偶不,爷爷)有一个跟st表非常类似的东西,f[i][j]表示j的第2^i的祖先,就是说f[0][x]是父亲,f[1][x]是爷爷,f[2][x]是高祖父(爷爷的爷爷),f[3][x]是远祖父(高祖父的高祖父) 搞个事: 按古制辈份分为:自己,父亲.祖父.曾祖.高祖.天祖.烈祖.太祖.远祖.鼻祖. 扯回来,这个就是倍增的思想,可以方便的实现O(logn)的LCA,现在让你在构图的时候…
参考:http://www.xuebuyuan.com/609502.html 先说题意: 给出一幅图,求最大生成树,并在这棵树上进行查询操作:给出两个结点编号x和y,求从x到y的路径上,由每个结点的权值构成的序列中的极差大小——要求,被减数要在减数的后面,即形成序列{a1,a2…aj …ak…an},求ak-aj (k>=j)的最大值. 求路径,显然用到lca. 太孤陋寡闻,才知道原来倍增dp能用来求LCA. 用p[u][i]表示结点u的第1<< i 个祖先结点,则有递推如下: for…
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入…
A - Breadth-First Search by Foxpower Time Limit:2000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Submit Status Description A - Breadth-First Search by Foxpower Problem Statement Fox Ciel went to JAG Kingdom by bicycle, but she forgot…
#include<cstdio> #include<iostream> #include<cstring> using namespace std; struct edge{ int next,to; edge(){ } edge(int a,int b){ next=a; to=b; } }E[];//建一个图…… ][],dep[],first[],tot; int n,m,root; void add_to_edge(int x,int y) { E[++t]=e…
官方题解: If you choose any n - 1 roads then price of reducing overall dissatisfaction is equal to min(c1, c2, ..cn - 1) where сi is price of reducing by 1 dissatisfaction of i-th edge. So the best solution is to choose one edge and reduce dissatisfactio…
题目链接:http://codevs.cn/problem/1036/ 今天翻箱倒柜的把这题翻出来做了,以前做的时候没怎么理解,所以今天来重做一下 这题是一个LCA裸题,基本上就把另一道裸题小机房的树拿出来改一改就行 但LCA也有两种方式,倍增和tarjan,倍增我个人觉得很好理解,tarjan就有点迷了 所以我就用了两种方式打这一道题 倍增: 倍增的做法就是数组f[i][j]表示从i点往上走2^j次方个点可以到达哪个点, 然后进行一个树上倍增,记录下一个深度dep,然后让我们求的两点到同一深度…
1.LCA LCA就是最近公共祖先(Least common ancestor),x,y的LCA记为z=LCA(x,y),满足z是x,y的公共祖先中深度最大的那一个(即离他们最近的那一个)qwq 2.问题引入 看LCA之前最好学一下并查集,因为这两个东西有点相似,不同之处在于并查集一旦进行了路径压缩,便只能求出两个点之间是否存在关系,无法精确判断谁是谁的祖先以及两者的深度最大的公共祖先(只能判断有没有公共祖先). 但LCA就不一样了,他可以实现并查集的操作,还可以查询两者的最近祖先,emm,关于…
概念 祖先 公共祖先 最近公共祖先 方法1:暴力爬山法 方法2:倍增 求公共祖先 求俩点的距离 Tarjan 概念 祖先 有根树中,一个节点到根的路径上的所有节点被视为这个点的祖先,包括根和它本身 公共祖先 对于点a和b,如果c既是a的祖先又是b的祖先,那么c是a和b的公共祖先 ##深度 子节点的深度=父节点深度+1,一般我们定根的深度为1 最近公共祖先 树上两个节点的所有公共祖先中,深度最大的那个称为两个点的最近公共祖先(LCA) 方法1:暴力爬山法 很明显,这个方法是很想爬山,我们可以先然两…
首先,什么是LCA? LCA:最近公共祖先 祖先:从当前点到根节点所经过的点,包括他自己,都是这个点的祖先 A和B的公共祖先:同时是A,B两点的祖先的点 A和B的最近公共祖先:深度最大的A和B的公共祖先 树上倍增:预处理nlog2n       求解nlog2n 原理大体描述:两个点都往上找,找到的第一个相同的点,就是他们的LCA 这里会有两个问题: Q1:若两个点深度不同,可能会错开 Q2:若真一个一个往上找,时间太慢 对于Q1,如果两个点深度不同,而我们又需要它们深度相同,那就想办法让他们深…
两个最近的点u和v的最近的公共的祖先称为最近公共祖先(LCA).普通的LCA算法,每算一次LCA的时间复杂度为线性o(n); 这里讲LCA + 二分的方法.首先对于任意的节点v,利用其父节点的信息,可以通过par2[v]=par[par[v]]得到向上走两步的节点.依此信息可以通过par4[v]=par2[par2[v]]得到向上走4步的节点.所以,根据此方法可以得到向上走2^k所得到的节点par[k][v].每次搜索的复杂度为o(log n),预处理par[k][v]的复杂度为o(nlog n…
struct Edge{ int from, to, nex; }edge[N<<1]; int head[N], edgenum; void addedge(int u, int v){ Edge E = {u, v, head[u]}; edge[ edgenum ] = E; head[u] = edgenum ++; } inline int Max(int a,int b){return a>b?a:b;} int time; int deep[N<<1], ind…
这题有毒!!!!!!!!!! TM我重新打的板子,然而...... 5分钟打完 debug两小时 我的写法常数太大了 每次DFS都要For去更新F 最后写了快读才A 改: 只处理f[i][0] dfs结束在处理f 整整快了一倍多!!!!!!!! 靠!! 烦.... #include<cstdio> #include<iostream> using namespace std; #define olinr return #define love_nmr 0 #define nmr 5…
第一步:建树  这个就不说了 第二部:分为两步  分别是深度预处理和祖先DP预处理 DP预处理: int i,j; ;(<<j)<n;j++) ;i<n;++i) ) fa[i][j]=fa[fa[i][j-]][j-];/*DP处理出i的2^j祖先是谁*/ 深度预处理: void dfs(int now,int from,int deepth) { deep[now]=deepth; for(int i=head[now];i;i=e[i].pre) if(e[i].v!=fro…
概况 LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 实现过程 预处理:通过dfs遍历,记录每个节点到根节点的距离dist[u],深度d[u] init()求出树上每个节点u的2^i祖先p[u][i] 求最近公共祖先,根据两个节点的的深度,如不同,向上调整深度大的节点,使得两个节点在同一层上,如果正好是祖先结束,否则,将两个节点同时上移,查询最近公共祖先. 代码: #include<bits/stdc++.h> #…
蒟蒻又来复习模板了.还WA了两次 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define R(a,b,c) for(register int a = (b); a <= (c); ++ a) #define nR(a,b,c) for(register int a = (b); a >=…
type arr=record v,nt:longint; end; ; lx=; ..maxn] of longint; eg:..maxn*] of arr; d:..maxn] of longint; g:..maxn,..lx] of longint; n,i,x,y,a,b,sum:longint; procedure swap(var a,b:longint); var c:longint; begin c:=a; a:=b; b:=c; end; procedure add(x,y…