【简介】

解决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 倍增法的更多相关文章

  1. luogu3379 【模板】最近公共祖先(LCA) 倍增法

    题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...

  2. 【lhyaaa】最近公共祖先LCA——倍增!!!

    高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...

  3. 最近公共祖先 LCA 倍增算法

          树上倍增求LCA LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 ...

  4. LCA(最近公共祖先)——LCA倍增法

    一.前人种树 博客:最近公共祖先 LCA 倍增法 博客:浅谈倍增法求LCA 二.沙场练兵 题目:POJ 1330 Nearest Common Ancestors 代码: const int MAXN ...

  5. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  6. 最近公共祖先(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- ...

  7. POJ - 1330 Nearest Common Ancestors(dfs+ST在线算法|LCA倍增法)

    1.输入树中的节点数N,输入树中的N-1条边.最后输入2个点,输出它们的最近公共祖先. 2.裸的最近公共祖先. 3. dfs+ST在线算法: /* LCA(POJ 1330) 在线算法 DFS+ST ...

  8. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  9. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

随机推荐

  1. php中的__call()函数重载

    <?php #调用类中没有的方法时, 会自动调用__call方法重载 #第一个参数是调用时的方法名, 第二个参数为参数组成的数组 class Cat{ public function Hello ...

  2. linux中字符串转换函数 simple_strtoul【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/7480087 Linux内核中提供的一些字符串转换函数: lib/vsprintf.c [htm ...

  3. ES的优化布局

    分词优化:IK Analyser Elastic Search 5.x官方提供的中文搜索并不友好,分词时经常将一句话分成很多单字,这时候可以使用IK Analyser插件进行优化,当然你在写java代 ...

  4. 用JavaScript简单判断浏览器类型

    判断浏览器类型 /** * 判断浏览器类型 * 返回表示浏览器类型的字符串 */ function whoIsMe(){ var explorer = navigator.userAgent; if( ...

  5. Leetcode 之Balanced Binary Tree(49)

    用递归的方式来做,左右两棵子树的高度差不超过1.分成两部分,一部分递归得到树的高度,一部分递归检查左右子树是否是平衡二叉树. int getHeight(TreeNode *root) { ; ; } ...

  6. vue css动画

    .toggle-cart-enter-active, .toggle-cart-leave-active { transition: all .3s ease-out; } .toggle-cart- ...

  7. 小程序的一个tab切换

    <view class="tab-left" bindtap="tab"> <view class="{{tabArr.curHdI ...

  8. 【转载】关于Python的Mixin模式

    本博按: mixin是看起来是多继承的一种,但是,这种继承并不作为父类存在,而是增加功能到子类中. 像C或C++这类语言都支持多重继承,一个子类可以有多个父类,这样的设计常被人诟病.因为继承应该是个” ...

  9. 【JBPM4】判断节点decision 方法2 condition

    运用condition计算并判断. JPDL <?xml version="1.0" encoding="UTF-8"?> <process ...

  10. WebDriver自动化测试工具(1)---环境搭建

    Webdriver是一个前端自动化测试工具,可以模拟用户点击链接,填写表单,点击按钮等操作,下面介绍其使用 一.下载WebdriverC#类库以及对应浏览器驱动 http://www.selenium ...