最近公共祖先 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 ...
随机推荐
- 一个python拖库字段的小脚本
import requests import re all_column = dict() all_db = "db_zf,dg_activity,dg_activity_log,dg_ad ...
- Python模块学习 - Fileinput
Fileinput模块 fileinput是python提供的标准库,使用fileinput模块可以依次读取命令行参数中给出的多个文件.也就是说,它可以遍历 sys.argv[1:],并按行读取列表中 ...
- 使用Redirector插件解决googleapis公共库加载的问题【转】
转自:http://www.cnblogs.com/kari/p/5860371.html 最近访问一些面向国外的网站总是会出现ajax.googleaips.com无法加载的情况.以下为加载stac ...
- gnu app url[web][5星]
http://www.gnu.org/software/software.zh-cn.html http://linux.chinaunix.net/news/2010/12/07/1175310.s ...
- C#调用Excel报 error CS1969: 找不到编译动态表达式所需的一个或多个类型。是否缺少引用?
转自[http://blog.csdn.net/bodybo/article/details/43191319] 程序需要读取Exel文件,有如下代码段 object oMissing = Syste ...
- FineReport——JS二次开发(CSS改变控件样式)
FR提供一些选择器,可以改变部分控件的样式,那么对于如何书写自己的css: 可以自己写css文件导入,也可以在页面加载结束事件中添加JS方法来改变css样式. 以文本框为例: 书写css文件,保存至% ...
- 使用 Visual Studio 部署 .NET Core 应用
可将 .NET Core 应用程序部署为依赖框架的部署或独立部署,前者包含应用程序二进制文件,但依赖目标系统上存在的 .NET Core,而后者同时包含应用程序和 .NET Core 二进制文件. 有 ...
- 【DUBBO】dubbo的Router接口
Router服务路由, 根据路由规则从多个Invoker中选出一个子集AbstractDirectory是所有目录服务实现的上层抽象, 它在list列举出所有invokers后,会在通过Router服 ...
- hdu 1399(水题)
Starship Hakodate-maru Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/O ...
- 自动选择profile
cobbler system list cobbler profile list 方式一:自动选择profile cobbler system add --name="linux-node1 ...