[学习笔记] 树上倍增求LCA
倍增这种东西,听起来挺高级,其实功能还没有线段树强大。线段树支持修改、查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨。
关于倍增思想:
倍增的思想很简单:通过区间[1,2i-1]与[1+2i-1,2i(2i-1+2i-1)]求出区间[1,2i]。
所以它可以用于区间求最值,求和。而到了树上之后,就变成了,求它往上任意次的祖先。
而倍增求LCA,就是用到了倍增这个功能。
倍增求LCA算法思路:
f[i,j],表示结点i,向上跳2j次跳到的点为f[i,j]。
显然f[i,0]中存的是i结点的父亲。
而f[i,j]=f[f[i,j-1],j-1],所以我们可以很简单的就求出f数组。
那么我们应该如何用它来求LCA呢?
两个结点a,b。(假设a的深度小于b)
首先我们让两个结点跳到同一深度(那个深度小跳到哪儿),这个过程可以用倍增来加速:从大到小枚举i,判断b往上跳2i是否会超过a,如果会,就不跳,不会,就跳。
这个为什么对于每个2i最多只会跳一次呢?
——你跳两次2i,我不会直接跳一次2i+1吗,动动脚趾都知道了嘛!
当它们处于同一高度时会产生两种情况:1、a=b,说明a本来就是b的祖先。2、a<>b,这个时候我们也是从大到小枚举i,判断a和b两者都向上跳2i次(假设此时在结点C,D)会不会重合,若重合,说明它们的LCA在C的下面,不跳,若不重合则说明LCA在C、D的上面,那么就让a跳到C,b跳到D。最后再把a(或b)往上跳1次,就是LCA了!
那么为什么最后要向上跳一次呢?
——如果在某时刻我们往上跳2i次就能跳到LCA的话,那么C就会与D重合,所以并不会跳上去,而是会往上跳(2i-1+2i-2+...+21+20)次。所以我们在最后取其父亲就能够得到LCA了。
代码:
var
f:array[0..100000,0..20]of longint;
next,dist,vet:array[0..200000]of longint;
x,y,z,a,b,i,j,k,n,m,tot,ans,sum:longint;
procedure add(x,y,z:longint);
begin
inc(tot);
next[tot]:=head[x];
vet[tot]:=y;
head[x]:=tot;
dist[tot]:=z;
end;
procedure dfs(u,dep:longint);
var
i,v:longint;
begin
depth[u]:=dep; vis[u]:=true;
for i:=1 to 20 do
f[u,i]:=f[f[u,i-1],i-1];
i:=head[u];
while i<>0 do
begin
v:=vet[i];
if not vis[v] then
begin
f[v,0]:=u;
dfs(v,dep+1);
end;
i:=next[i];
end;
end;
function lca(a,b:longint):longint;
var
i,t:longint;
begin
if depth[a]>depth[b] then begin t:=a; a:=b; b:=t; end;
for i:=20 downto 0 do
if depth[f[b,i]]>=depth[a] then b:=f[b,i];
if a=b then exit(a);
for i:=20 downto 0 do
if f[a,i]<>f[b,i] then
begin
a:=f[a,i]; b:=f[b,i];
end;
exit(f[a,0]);
end;
begin
read(n);
for i:=1 to n-1 do
begin
read(x,y,z);
add(x,y,z); add(y,x,z);
end;
dfs(1,1);
read(m);
for i:=1 to m do
begin
read(x,y);
writeln(lca(x,y));
end;
end.
[学习笔记] 树上倍增求LCA的更多相关文章
- 树上倍增求LCA(最近公共祖先)
前几天做faebdc学长出的模拟题,第三题最后要倍增来优化,在学长的讲解下,尝试的学习和编了一下倍增求LCA(我能说我其他方法也大会吗?..) 倍增求LCA: father[i][j]表示节点i往上跳 ...
- [算法]树上倍增求LCA
LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4 ...
- 树上倍增求LCA及例题
先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...
- Codeforces 609E (Kruskal求最小生成树+树上倍增求LCA)
题面 传送门 题目大意: 给定一个无向连通带权图G,对于每条边(u,v,w)" role="presentation" style="position: rel ...
- 树上倍增求LCA详解
LCA(least common ancestors)最近公共祖先 指的就是对于一棵有根树,若结点z既是x的祖先,也是y的祖先(不要告诉我你不知道什么是祖先),那么z就是结点x和y的最近公共祖先. 定 ...
- [luogu3379]最近公共祖先(树上倍增求LCA)
题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板(最好采用第一种,第二种纯粹是习惯) #include<cstdio> #includ ...
- CF 519E(树上倍增求lca)
传送门:A and B and Lecture Rooms 题意:给定一棵树,每次询问到达点u,v距离相等的点有多少个. 分析:按情况考虑: 1.abs(deep[u]-deep[v])%2==1时, ...
- 树上倍增求LCA
大概思想就是,节点$i$的第$2^{j}$个父节点是他第$2^{j-1}$个父亲的第$2^{j-1}$个父亲 然后可以$O(nlogn)$时间内解决…… 没了? //fa[i][j]表示i的第2^j个 ...
- 倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))
倍增求\(LCA\) 倍增基础 从字面意思理解,倍增就是"成倍增长". 一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\ ...
随机推荐
- Prometheus监控神器-服务发现篇(二)
本章节讲解服务发现与Relabelling的机制与范例. 通过服务发现的方式,我们可以在不重启Prometheus服务的情况下动态的发现需要监控的Target实例信息. 如上图所示,对于线上环境我们可 ...
- 14_Web服务器-并发服务器
1.服务器概述 1.硬件服务器(IBM,HP): 主机 集群 2.软件服务器(HTTPserver Django flask): 网络服务器,在后端提供网络功能逻辑处理数据处理的程序或者架构等 3.服 ...
- C#编辑GridView的Thead
背景 有这样一个需求,需要更改GridView的Thead,即表头.不只是多行表头,而是任意的内容,可能是一段文字,也可能是一个图片,综合网上的一些资料,大致整理出一些做法. 内容 大致有两种方法 第 ...
- Fastbin attack——Double Free
ptmalloc ptmalloc的基本思路是将堆上的内存区域划分为多个chunk,在分配/回收内存时,对chunk进行分割.回收等操作.在32位系统下,chunk头的大小为8 Bytes,且每个ch ...
- 月薪20k的java面试题他来了
1.场景描述 最近有朋友私信,说网上的面试资料有点散,还有些过时的,问老王能否帮忙整理下,老王晚上刚好有空,就给梳理了下,分享给大家. 2.解决方案 2.1 说明 (1)面试的题目多数是从网上找的,老 ...
- Linux常用命令详解(1)
基础命令:lsmanpwdcdmkdirechotouchcpmvrmrmdircatmorelessheadtailclearpoweroffreboot进阶命令(下一章节):aliasunalia ...
- TX-LCN分布式事务框架使用
官方文档相关: GitHub地址:https://github.com/codingapi/tx-lcn 官方文档:https://www.codingapi.com/docs/txlcn-prefa ...
- 【转】Locust性能-零基础入门系列(2) -重写wait_time
在虚拟模拟的时候,可能对等待时间有更高的要求,比如假如有这么一个场景要求:某任务要求每被执行1次,那么下次的等待时间就1秒钟.这种情况,是可以实现的,这也就体现了Locust的灵活性.可编程性,很多比 ...
- 阿里云恶意软件检测比赛-第三周-TextCNN
LSTM初试遇到障碍,使用较熟悉的TextCNN. 1.基础知识: Embedding:将词的十进制表示做向量化 起到降维增维的作用 嵌入维度数量(New Embedding维度)的一般经验法则: e ...
- 种子爆破&[GWCTF 2019]枯燥的抽奖
伪随机数的爆破,种子爆破 做到了一道题,就是有个伪随机数爆破的漏洞,当时尽管是看到了这两个敏感的函数,但是先去看其他的了,没有看到什么漏洞,所以我当时是准备直接强行爆破,之后看到使用伪随机数爆破的方式 ...