一、什么是LCA?

LCA:Least Common Ancestors(最近公共祖先),对于一棵有根树T的任意两个节点u,v,求出LCA(T, u, v),即离跟最远的节点x,使得x同时是u和v的祖先。

二、算法分类

  求LCA的算法很多,按照是否在线可以分为在线算法和离线算法。
      在线算法:用比较长的时间做预处理,但是等信息充足以后每次回答询问只需要用比较少的时间。
      离线算法:先把所有的询问读入,然后一起把所有询问回答完成,不是本文所讲,Click here

三、在线算法

  (1)什么是RMQ?

  RMQ:给出一个数组A,回答询问RMQ(A, i, j),即A[i...j]之间的最值的下标。

  (2)RMQ算法,不是本文所讲,Click here

  (3)RMQ与LCA 

  假设一颗有根树,如图所示:

  

  我们可以通过深搜(从1节点开始)得到这样一个序列:

  欧拉序列V:1 2 1 3 4 3 5 6 5 7 5 3 1

  深度序列D:0 1 0 1 2 1 2 3 2 3 2 1 0

  First:1 2 4 5 7 8 10

  First表示节点i在欧拉序列V中第一次出现的位置

  

  现在比如我们要求LCA(4,7)

  那么找到节点4和7第一次出现的位置即:First(4)=5,First(7)=10

  对应到欧拉序列V中区间[5,10]即:4 3 5 6 5 7

  发现正好是以3为根的子树,然我我们找到这几个数中深度最小的即D(3),说明3就是4和7的最近公共祖先

  同理再比如说要求LCA(2,5),First(2)=2,First(5)=7,找到对应区间[2,7]即2 1 3 4 3 5

  然后找到深度最小的即1,说明1就是2和5的最近公共祖先。

四:例题

  HDU 2586

  AC CODE:

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
#define N 40010
#define M N*2 struct edge
{
int u,v,w,next;
}edge[M];
int tot,head[N]; int n,m;
int idx;
bool vis[N];
int ver[*N];
int dep[*N];
int first[N];
int dis[N];
int dp[*N][]; void init()
{
tot=;
memset(head,-,sizeof(head));
}
void add(int u,int v,int w)
{
edge[tot].u=u;
edge[tot].v=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
void init2()
{
idx=;
dis[]=;
memset(vis,,sizeof(vis));
}
void dfs(int u,int d)
{
vis[u]=;
ver[++idx]=u;
first[u]=idx;
dep[idx]=d;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(!vis[v]){
int w=edge[i].w;
dis[v]=dis[u]+w;
dfs(v,d+);
ver[++idx]=u;
dep[idx]=d;
}
}
}
void ST(int n)
{
int i,j;
for(i=;i<=n;i++) dp[i][]=i;
for(j=;(<<j)<=n;j++){
for(i=;i<=n;i++){
if(i+(<<j)-<=n){
int a=dp[i][j-];
int b=dp[i+(<<(j-))][j-];
dp[i][j]=dep[a]<dep[b]?a:b;
}
}
}
}
int RMQ(int i,int j)
{
int k=(int)(log((double)(j-i+))/log(2.0));
int a=dp[i][k],b=dp[j-(<<k)+][k];
return dep[a]<dep[b]?a:b;
}
int LCA(int u,int v)
{
int x=first[u];
int y=first[v];
if(x>y) swap(x,y);
int res=RMQ(x,y);
return ver[res];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
init2();
dfs(,);
ST(*n-);
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
int lca=LCA(u,v);
printf("%d\n",dis[u]+dis[v]-*dis[lca]);
}
}
return ;
}

LCA与RMQ的更多相关文章

  1. LCA和RMQ

    下面写提供几个学习LCA和RMQ的博客,都很通熟易懂 http://dongxicheng.org/structure/lca-rmq/ 这个应该是讲得最好的,且博主还有很多其他文章,可以读读,感觉认 ...

  2. ZOJ 3195 Design the city LCA转RMQ

    题意:给定n个点,下面n-1行 u , v ,dis 表示一条无向边和边权值,这里给了一颗无向树 下面m表示m个询问,问 u v n 三点最短距离 典型的LCA转RMQ #include<std ...

  3. [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]

    参考: 1. 郭华阳 - 算法合集之<RMQ与LCA问题>. 讲得很清楚! 2. http://www.cnblogs.com/lazycal/archive/2012/08/11/263 ...

  4. lca转RMQ

    这个博客写得好 #include <stdio.h> #include <vector> #include <string.h> using namespace s ...

  5. HDU 3078 LCA转RMQ

    题意: n个点 m个询问 下面n个数字表示点权值 n-1行给定一棵树 m个询问 k u v k为0时把u点权值改为v 或者问 u-v的路径上 第k大的数 思路: LCA转RMQ求出 LCA(u,v) ...

  6. 【51NOD1766】树上的最远点对(线段树,LCA,RMQ)

    题意:n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间, 表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c< ...

  7. POJ 1986(LCA and RMQ)

    题意:给定一棵树,求任意两点之间的距离. 思路:由于树的特殊性,所以任意两点之间的路径是唯一的.u到v的距离等于dis(u) + dis(v) - 2 * dis(lca(u, v)); 其中dis( ...

  8. HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)

    题目地址:HDU 5266 这题用转RMQ求LCA的方法来做的很easy,仅仅须要找到l-r区间内的dfs序最大的和最小的就能够.那么用线段树或者RMQ维护一下区间最值就能够了.然后就是找dfs序最大 ...

  9. LCA(包含RMQ)

    今天看了RMQ问题 ST的实质是动归 于是我来回顾一下LCA(的各种写法) 因为每次考试发现自己连LCA都写不好 费时 First of all, RMQ板子: [一维] #include<bi ...

随机推荐

  1. JavaScript的常见事件和Ajax小结

    一.常见事件类型 1.鼠标事件 事件名称 说明 onclick 鼠标单击时触发 ondbclick 鼠标双击时触发 onmousedown 鼠标左键按下时触发 onmouseup 鼠标释放时触发 on ...

  2. Security log is full,only administrator can log on to fix the problem(安全日志满了)

    When you login the system and see this error  “Security log on this system is full,only administrato ...

  3. XSS前端防火墙

    前一段时间,在EtherDream大神的博客里看到关于XSS防火墙的一系列文章,觉得很有意思.刚好科创要做一个防火墙,就把XSS前端防火墙作为一个创新点,着手去实现了. 在实现过程中,由于各种原因,比 ...

  4. jvm 参数调优

    FROM: http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html#CMSInitiatingOccupancyFraction ...

  5. 监控SQL Server的job执行情况

    在服务器没有设置发邮件并且不允许发邮件的情况下, 可以通过下列语句来检查SQL Server 的job的执行情况 select top 150 a.run_date,a.run_time, b.nam ...

  6. bnuoj 27987 Record of the Attack at the Orbit (模拟)

    http://www.bnuoj.com/bnuoj/problem_show.php?pid=27987 [题意]:给定坐标输出图形 [题解]:处理坐标上的小技巧 [code]: #include ...

  7. iOS 状态栏管理

    iOS 7 以前:状态栏由 UIApplication 管理 1.隐藏状态栏 : application.statusBarHidden = NO; 2.设置状态栏样式 : application.s ...

  8. centos最小安装 setuptools安装

    centos运行不了setup?那安装setuptool吧,可以节省很多系统管理的时间. #安装setuptoolyum install setuptool#可以发现执行setup后不全,再安装一个用 ...

  9. OD之窗口界面

  10. 用CodeViz绘制函数调用关系图(call graph)

    CodeViz是<Understanding The Linux Virtual Memory Manager>(at Amazon,下载地址在页尾)的作者 Mel Gorman 写的一款 ...