最近公共祖先 LCA 倍增法
【简介】
解决LCA问题的倍增法是一种基于倍增思想的在线算法。
【原理】
原理和同样是使用倍增思想的RMQ-ST 算法类似,比较简单,想清楚后很容易实现。
对于每个节点u , ancestors[u][k] 表示 u 的第2k个祖先是谁。很容易就想到递推式: ancestors[j][i] = ancestors[ancestors[j][i - 1]][i - 1]; 根据二进制原理,理论上 u 的所有祖先都可以根据ancestors数组多次跳转得到,这样就间接地记录了每个节点的祖先信息。
查询LCA(u,v)的时候:
(一)u和v所在的树的层数如果一样,令u'=u。否则需要平衡操作(假设u更深),先找到u的一个祖先u', 使得u'的层数和v一样,此时LCA(u,v)=LCA(u',v) 。证明很简单:如果LCA(u,v)=v , 那么u'一定等于v ;如果LCA(u,v)=k ,k!=v ,那么k 的深度一定小于 v , u、u'、v 一定在k的子树中;综上所述,LCA(u,v)=LCA(u',v)一定成立。
(二)此时u' 和 v 的祖先序列中一开始的部分一定有所重叠,重叠部分的最后一个元素(也就是深度最深,与u'、v最近的元素)就是所求的LCA(u,v)。这里ancestors数组就可以派上用场了。找到第一个不重叠的节点k,LCA(u,v)=ancestors[k][0] 。 找k的过程利用二进制贪心思想,先尽可能跳到最上层的祖先,如果两祖先相等,说明完全可以跳小点,跳的距离除2,这样一步步跳下去一定可以找到k。
【hdu 2586】
需要注意的是超界的处理。
- #pragma comment(linker, "/STACK:1024000000,1024000000")
- #include <stdio.h>
- #include <string.h>
- #include <vector>
- #include <cmath>
- #include <iostream>
- using namespace std;
- int n,m;
- struct edge
- {
- int d,v,next;
- edge(){}
- edge(int _d,int _v,int _next)
- {
- d=_d;v=_v;next=_next;
- }
- }data[];
- int map[];
- int pool;
- void addedge(int s,int e,int v)
- {
- int t=map[s];
- data[pool++]=edge(e,v,t);
- map[s]=pool-;
- }
- int ANCLOG;
- int depth[];
- int ifv[];
- int dis[];
- int anc[][];
- void dfs(int cur,int dep)
- {
- ifv[cur]=;
- depth[cur]=dep;
- int p=map[cur];
- while (p!=-)
- {
- if (!ifv[data[p].d])
- {
- dis[data[p].d]=dis[cur]+data[p].v;
- anc[data[p].d][]=cur;
- dfs(data[p].d,dep+);
- }
- p=data[p].next;
- }
- }
- void initLCA()
- {
- for (int k=;k<ANCLOG;++k)
- for (int i=;i<n;++i)
- {
- if (anc[i][k-]==-) continue;
- anc[i][k]=anc[anc[i][k-]][k-];
- }
- }
- int getLCA(int u,int v)
- {
- if (depth[u]<depth[v]) swap(u,v);
- for (int k=ANCLOG;k>=;--k)
- {
- if (anc[u][k]==-) continue;
- if (depth[anc[u][k]]>=depth[v])
- {
- u=anc[u][k];
- if (depth[u]==depth[v]) break;
- }
- }
- if (u==v) return u;
- for (int k=ANCLOG;k>=;--k)
- {
- if (anc[u][k]==-) continue;
- if (anc[u][k]!=anc[v][k])
- {
- u=anc[u][k];
- v=anc[v][k];
- }
- }
- return anc[u][];
- }
- int main()
- {
- int T;
- scanf("%d",&T);
- while (T--)
- {
- pool=;
- memset(anc,-,sizeof anc);
- memset(map,-,sizeof map);
- memset(ifv,,sizeof ifv);
- scanf("%d%d",&n,&m);
- ANCLOG=(int)(log(n)/log(2.0));
- int s,e,v;
- for (int i=;i<n-;++i)
- {
- scanf("%d%d%d",&s,&e,&v);
- addedge(s-,e-,v);
- addedge(e-,s-,v);
- }
- dis[]=;
- dfs(,);
- initLCA();
- for (int i=;i<m;++i)
- {
- int u,v;
- scanf("%d%d",&u,&v);
- --u;--v;
- int k=getLCA(u,v);
- k=dis[u]+dis[v]-*dis[k];
- printf("%d\n",k);
- }
- }
- }
最近公共祖先 LCA 倍增法的更多相关文章
- luogu3379 【模板】最近公共祖先(LCA) 倍增法
题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- 最近公共祖先 LCA 倍增算法
树上倍增求LCA LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 ...
- LCA(最近公共祖先)——LCA倍增法
一.前人种树 博客:最近公共祖先 LCA 倍增法 博客:浅谈倍增法求LCA 二.沙场练兵 题目:POJ 1330 Nearest Common Ancestors 代码: const int MAXN ...
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- 最近公共祖先(LCA)的三种求解方法
转载来自:https://blog.andrewei.info/2015/10/08/e6-9c-80-e8-bf-91-e5-85-ac-e5-85-b1-e7-a5-96-e5-85-88lca- ...
- POJ - 1330 Nearest Common Ancestors(dfs+ST在线算法|LCA倍增法)
1.输入树中的节点数N,输入树中的N-1条边.最后输入2个点,输出它们的最近公共祖先. 2.裸的最近公共祖先. 3. dfs+ST在线算法: /* LCA(POJ 1330) 在线算法 DFS+ST ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
随机推荐
- Perl6 Bailador框架(3):路径匹配
use v6; use Bailador; =begin pod 注意的是, 当/:one设置时 虽然你有/admin或/about, 但这个/:one不会跟现有的匹配 只跟没有的匹配: 也就是说, ...
- Xmind 8 update5 破解
Step 1. Download XMind Step 2. Run XMind at least once after installation, xmind will init the confi ...
- python基础===时间处理模块
时间模块 Python中有很多方便我们处理时间信息的模块 time 模块 datetime 模块 pytz 模块 dateutil 模块 这里我们着重介绍的是前两种 time模块 time.time( ...
- FreeRADIUS + MySQL 安装配置笔记
FreeRADIUS + MySQL 安装配置笔记 https://www.2cto.com/net/201110/106597.html
- xshell+xming连接服务器虚拟机启动mininet网络
困于vnc连实验室的服务器虚拟机,一直出现页面不稳定的情况,然后本机虚拟机又带不起来,今天跟学弟交流,知道了ssh连接服务器的办法,心情好晴朗! xshell下载和安装,xshell使用 xshell ...
- python的IDLE界面回退代码语句
Alt+P回退到IDLE中之前输入的代码语句 Alt+N可以移至下一个代码语句
- Hadoop(hadoop,HBase)组件import到eclipse
1.简介: 将源代码import到eclipse可以方便的阅读和修改源码. 2.环境说明: mac mvn工具(Apache Maven 3.3.3 ) 3.hadoop(CDH5.4.2) 1.进入 ...
- ZOJ-2753
Min Cut (Destroy Trade Net) Time Limit: 15 Seconds Memory Limit: 32768 KB Given an undirected g ...
- highcharts 折线,饼状,条状综合图
完整代码如下: <head> <meta http-equiv="Content-Type" content="text/html; charset=u ...
- 常用模块二(hashlib、configparser、logging)
阅读目录 常用模块二 hashlib模块 configparse模块 logging模块 常用模块二 返回顶部 hashlib模块 Python的hashlib提供了常见的摘要算法,如MD5,SH ...