LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。 (来自百度百科)


一.倍增求LCA

预处理出距点u距离为2^0,2^1,2^2...的点作为f[u][0],f[u][1],f[u][2]...

d[u]记录点u的深度

用二进制拆分的思想,让更深的点向上跳,直至与另一个点深度相同

此时,如果两个点重合了,那么那个浅的点本身就是最近公共祖先

若两个点没有重合,则继续按二进制拆分的思想,两个点同时跳相同高度,跳过了就跳短一些,直至两个点重合

 #include<cstdio>
#include<iostream>
#include<cmath>
#define R register int
using namespace std;
const int N=;
inline int g() {
R ret=,fix=; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-:fix;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret*fix;
}
struct node{
int v,nxt;
#define v(i) e[i].v
#define nxt(i) e[i].nxt
}e[N<<];
int n,m,s,cnt;
int fir[N],d[N],f[N][];
inline void add(int u,int v) {v(++cnt)=v,nxt(cnt)=fir[u],fir[u]=cnt;}
inline void dfs(int u) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(d[v]) continue;
d[v]=d[u]+; f[v][]=u; R p=u;
for(R j=;f[p][j];++j) f[v][j+]=f[p][j],p=f[p][j];
dfs(v);
}
}
inline int ask(int u,int v) {
if(d[v]>d[u]) swap(u,v);
R lim=log2(d[u])+;
for(R i=lim;i>=;--i) if(d[f[u][i]]>=d[v]) u=f[u][i];
if(u==v) return u;
for(R i=lim;i>=;--i) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][];
}
signed main() {
n=g(),m=g(),s=g();//n为结点数,m为询问次数,s为根节点
for(R i=,u,v;i<n;++i) u=g(),v=g(),add(u,v),add(v,u);
d[s]=; dfs(s);
for(R i=;i<=m;++i) {
R u=g(),v=g();
printf("%d\n",ask(u,v));
}
}

二.tarjan求LCA

Tarjan是的离线的

从根结点开始dfs,对遍历到的结点u标记已访问,创建新集合,元素为u,再遍历u的每一个子节点v,回溯时将每个子节点v的集合并到u的集合上,用并查集记录集合中的每个元素的fa为u,接着处理询问,对于关于u的每一个询问,若另一个结点v已访问,则可断定LCA(u,v)为fa[v],记录结果,最后按顺序输出即可

 #include<cstdio>
#include<iostream>
#define R register int
const int N=;
using namespace std;
inline int g() {
R ret=,fix=; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-:fix;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret*fix;
}
struct node{
int v,nxt;
#define v(i) e[i].v
#define nxt(i) e[i].nxt
#define vv(i) q[i].v
#define nn(i) q[i].nxt
}e[N<<],q[N<<];
int n,m,s,cnt,cntq;
int fir[N],fq[N],lca[N],fa[N];
bool vis[N],vq[N];
inline void add(int u,int v) {v(++cnt)=v,nxt(cnt)=fir[u],fir[u]=cnt;}
inline void addq(int u,int v) {vv(++cntq)=v,nn(cntq)=fq[u],fq[u]=cntq;}
inline int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
inline void tarjan(int u) {
vis[u]=true;
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(vis[v]) continue;
tarjan(v);
fa[getf(v)]=u;
}
for(R i=fq[u];i;i=nn(i)) {
R v=vv(i);
if(vis[v]&&!vq[(i+)>>]) lca[(i+)>>]=getf(v),vq[(i+)>>]=true;
}
}
signed main(){
n=g(),m=g(),s=g();
for(R i=;i<=n;++i) fa[i]=i;
for(R i=,u,v;i<n;++i) u=g(),v=g(),add(u,v),add(v,u);
for(R i=,u,v;i<=m;++i) u=g(),v=g(),addq(u,v),addq(v,u);
tarjan(s);
for(R i=;i<=m;++i) printf("%d\n",lca[i]);
}

2019.04.02

浅谈最近公共祖先(LCA)的更多相关文章

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

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

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

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

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

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

  4. [模板] 最近公共祖先/lca

    简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...

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

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

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

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

  7. 最近公共祖先 lca (施工ing)

    声明 咳咳,进入重难点的图论算法之一(敲黑板): 题目: 洛谷 P3379 先放标程,施工ing,以后补坑!!!(实在太难,一个模板这么长 [ 不过好像还是没有 AC自动机 长哎 ],注释都打半天,思 ...

  8. 求最近公共祖先(LCA)的各种算法

    水一发题解. 我只是想存一下树剖LCA的代码...... 以洛谷上的这个模板为例:P3379 [模板]最近公共祖先(LCA) 1.朴素LCA 就像做模拟题一样,先dfs找到基本信息:每个节点的父亲.深 ...

  9. 与图论的邂逅05:最近公共祖先LCA

    什么是LCA? 祖先链 对于一棵树T,若它的根节点是r,对于任意一个树上的节点x,从r走到x的路径是唯一的(显然),那么这条路径上的点都是并且只有这些点是x的祖先.这些点组成的链(或者说路径)就是x的 ...

随机推荐

  1. the art of seo(chapter eight)

    How Social Media and User Data Play a Role in Search Results and Rankings ***Correlation Between Soc ...

  2. storm源码剖析(2):storm的配置项

    storm的配置项,可以从backtype/storm/Config.java中找到所有配置项及其描述

  3. 《java编程思想》:设计模式(不定期更新)

    1.策略设计模式 创建一个能够根据所传递的参数对象的不同而具有不同的方法,被称为策略设计模式.这类方法包含索要执行的算法中固定不变的部分,而“策略”包含变化的部分.策略就是传递进去的参数对象.在下面的 ...

  4. 二:apache的Qpid消息中间件介绍

    一:什么是Qpid?--->Qpid 是 Apache 开发的一款面向对象的消息中间件,它是一个 AMQP 的实现,可以和其他符合 AMQP 协议的系统进行通信.--->Qpid 提供了 ...

  5. Jenkins持续集成环境搭建

    1部署Jenkins Jenkins部署很简单,只需建立一个新应用,将Jenkins的war包部署进去,再分配好权限就可以了. 1.1创建应用 建立一个新Nginx应用:jenkins.com 1.2 ...

  6. Happy Great BG-卡精度

    Happy Great BG Time Limit: 2000ms Case Time Limit: 2000ms Memory Limit: 65536KB   64-bit integer IO ...

  7. 【Jmeter】Jmeter聚合报告分析

    Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,这里显示的就是 Name 属性的值 #Samples:表示你这次测试中一共发出了多少个请求 ...

  8. Java关键字以及一些基础解释

    Java Se:Java Me 和Java Ee的基础,允许开发和部署在桌面,服务器,嵌入式环境和实时环境中使用的java程序,支持java web服务开发类 java ee:是目前java技术应用最 ...

  9. python3 + selenium + eclipse 中报错:'geckodriver' executable needs to be in PATH

    Windows系统解决办法如下: 1.下载geckodriver.exe: 下载地址:https://github.com/mozilla/geckodriver/releases 请根据系统版本选择 ...

  10. <正则吃饺子> :关于oracle 中 exists 、not exists 的简单使用

    话不多说,简单的总结而已.网络上很多很详细介绍. 例如,博文:http://blog.csdn.net/zhiweianran/article/details/7868894  当然这篇也是转载的,原 ...