1,最近公共祖先(LCA):
对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。
2,LCA问题向RMQ问题的转化方法:(RMQ返回最值的下标)
对树进行深度优先遍历,每当“进入”或回溯到某个结点时,将这个结点的深度存入数组dfsNum最后一位。同时记录结点i在数组中第一次出现的位置(事实上就是进入结点i时记录的位置),记做first[i]。如果结点dfsNum[i]的深度记做depth[i],易见,这时求LCA(u,v),就等价于求 E[RMQ(depth,first[u],first[v])],(first[u]<first[v])。
例如:
(深度遍历)difNum[i]为:1,2,1,3,4,3,5,3,1
first[i]为:0,1,3,4,6
(个点对应的深度)depth[i]为:0,1,0,1,2,1,2,1,0
于是有:
LCA(4,2) = difNum[RMQ(D,first[2],first[4])] = difNum[RMQ(D,1,6)] = difNum[2] = 1
对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。
2,LCA问题向RMQ问题的转化方法:(RMQ返回最值的下标)
对树进行深度优先遍历,每当“进入”或回溯到某个结点时,将这个结点的深度存入数组dfsNum最后一位。同时记录结点i在数组中第一次出现的位置(事实上就是进入结点i时记录的位置),记做first[i]。如果结点dfsNum[i]的深度记做depth[i],易见,这时求LCA(u,v),就等价于求 E[RMQ(depth,first[u],first[v])],(first[u]<first[v])。
例如:
(深度遍历)difNum[i]为:1,2,1,3,4,3,5,3,1
first[i]为:0,1,3,4,6
(个点对应的深度)depth[i]为:0,1,0,1,2,1,2,1,0
于是有:
LCA(4,2) = difNum[RMQ(D,first[2],first[4])] = difNum[RMQ(D,1,6)] = difNum[2] = 1
转化后得到的数列长度为树的结点数*2-1(每经过一条边,都会记录端点,有N-1条边,所以会回溯N-1次。且每个顶点都会被添加一次,所以长度为2N-1)
转自:http://kmplayer.iteye.com/blog/604232
//poj 1330 lca&&rmq 在线算法
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
const long M=31000;
struct LCA{
long head[M],to[M],next[M],edge_cnt;
long dfsNum[M],depth[M],first[M],dfs_cnt;
long rmq[M][30],n;
void init_edge(){
memset(head,-1,sizeof(head));
edge_cnt=0; dfs_cnt=0;
}
void add_edge(long u,long v){
next[edge_cnt]=head[u]; to[edge_cnt]=v; head[u]=edge_cnt++;
}
void dfs(long u,long fa,long dep){
dfsNum[dfs_cnt]=u;
depth[dfs_cnt]=dep;
first[u]=dfs_cnt++;
for (long i=head[u];i!=-1;i=next[i]){
long v=to[i];
if (v==fa) continue;
dfs(v,u,dep+1);
dfsNum[dfs_cnt]=u;
depth[dfs_cnt]=dep;
dfs_cnt++;
}
}
void init_rmq(){
n=dfs_cnt;
for (long i=0;i<n;++i) rmq[i][0]=i;
for (long j=1;(1<<j)<=n;++j)
for (long i=0;i+(1<<j)-1<n;++i)
rmq[i][j]=(depth[rmq[i][j-1]]<depth[rmq[i+(1<<(j-1))][j-1]])?
rmq[i][j-1]:rmq[i+(1<<(j-1))][j-1];
}
long rmqIndex(long l,long r){
if (l>r) std::swap(l,r);
int k=(int)(log((r-l+1)*1.0)/log(2.0));
return (depth[rmq[l][k]]<depth[rmq[r-(1<<k)+1][k]])?
rmq[l][k]:rmq[r-(1<<k)+1][k];
}
long lca(long u,long v){
return dfsNum[rmqIndex(first[u],first[v])];
}
}G;
long t,vis[M],root;
int main(){
scanf("%d",&t);
while (t--){
long n;
G.init_edge();
scanf("%d",&n);
long u,v;
memset(vis,0,sizeof(vis));
for (long i=1;i<n;++i){
scanf("%d%d",&u,&v);
G.add_edge(u,v);
//G.add_edge(v,u);
vis[v]=1;
}
for (long i=1;i<=n;++i)
if (!vis[i]){ root=i; break;}
G.dfs(root,-1,0);
G.init_rmq();
scanf("%d%d",&u,&v);
printf("%d\n",G.lca(u,v));
}
return 0;
}