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. BZOJ 1601 [Usaco2008 Oct]灌水:最小生成树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1601 题意: Farmer John已经决定把水灌到他的n(1<=n<=300 ...

  2. PHP之面向对象PHP之面向对象(面向对象是什么)

    PHP之面向对象(面向对象是什么) 一.总结 一句话总结: 面向对象就是类:类都要 属性 和 方法 比如人:属性比如身高体重,方法比如吃饭喝水 面向对象中 ,方法即是函数 : 属性即是变量 ,只是面相 ...

  3. DBA日记:一次reboot导致的严重失误

    昨天下午,一现场要添加RAC节点,db1节点正常运行,添加db2节点:在db2上做了安装的一些配置后,需要reboot, 于是直接就reboot:糟糕,这条命令错误地执行在db1上了,导致现场数据库直 ...

  4. 机器学习 F1-Score, recall, precision

    在机器学习,模式识别中,我们做分类的时候,会用到一些指标来评判算法的优劣,最常用的就是识别率,简单来说,就是 Acc=Npre/Ntotal 这里的 Npre表示预测对的样本数,Ntotal表示测试集 ...

  5. <<Senium2自动化测试>>读书笔记二

    为进一步加强Python知识扩展和学习,在朋友的推荐下选择了<<Selenium2自动化测试实战>>,作者胡志恒,基于Python语言实现,以实例的方式详细讲解WebDrive ...

  6. 【C】字符串常量和字符数组

    此次博客是转载某位博主的文章,不过现在找不到了,所以先声明一下. 先贴一段代码: #include <stdio.h> int main(int argc, const char** ar ...

  7. 【QT】《转载》常用快捷键

    F1        查看帮助F2        跳转到函数定义(和Ctrl+鼠标左键一样的效果)Shift+F2    声明和定义之间切换F4        头文件和源文件之间切换Ctrl+1     ...

  8. 【Lintcode】177.Convert Sorted Array to Binary Search Tree With Minimal Height

    题目: Given a sorted (increasing order) array, Convert it to create a binary tree with minimal height. ...

  9. 规划ASM DISK GROUP、查看asm 磁盘当前状态、mount or dismount 磁盘组、检查磁盘组 metadata 的内部一致性

    规划ASM DISK GROUP: 1. 每个磁盘组里的磁盘应该大小.性能.新旧等一致,不能有太大差距 2. 对database files 和 fast recovery area 分别创建不同的d ...

  10. ASP.Net MVC实现一个表单多个submit

    1. 用Html.BeginForm(ActionName,ControllerName,Post)来实现controller-action的路由, 2. Form里的每个input的name值统一, ...