概念

公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点

举个例子吧,如下图所示45最近公共祖先的最近公共祖先是最近公共祖先

算法

常用的求LCA的算法有:Tarjan/DFS+ST/倍增

其中 :ST和倍增都是在线的;Taijian是离线的

这里介绍离线的Tarjian算法

基本思想:

1.任选一个点为根节点,从根节点开始

2.遍历该点u所有子节点v,并标记这些子节点v已被访问过

3.若是v还有子节点,返回2,否则下一步

4.合并v到u上

5.寻找与当前点u有询问关系的点v

6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a。

代码


#include<cstdio>
#include<iostream>
#include<cstring>
#define N 5200000
struct data {
int next;
int to;
int lca; //存每一次询问的答案
};
data edge[N];
data qedge[N];
int n,m,p,x,y;
int tot_edge,tot_qedge,head[N],qhead[N];
int fa[N];
int visit[N];
template<typename T>inline void read(T&x){
x=0;T y=1;char c;
while(c=getchar(),c<48||57<c) if(c=='-')y=-1;x=c^48;
while(c=getchar(),47<c&&c<58) x=(x<<1)+(x<<3)+(c^48);x*=y;
}
void add_edge(int u,int v) {
edge[++tot_edge].next=head[u];
edge[tot_edge].to=v;
head[u]=tot_edge;
}
void add_qedge(int u,int v) { //建立需要查询LCA的两节点的链表
qedge[++tot_qedge].next=qhead[u];
qedge[tot_qedge].to=v;
qhead[u]=tot_qedge;
}
int find(int z) {
return fa[z]==z?z:find(fa[z]);
/*if(fa[z]!=z)
fa[z]=find(fa[z]);
return fa[z];*/
}
int dfs(int x) { //把整棵树的一部分看作以节点x为根节点的小树
fa[x]=x; //由于节点x被看作是根节点,所以把x的fa设为它自己
visit[x]=1; //标记为已被搜索过
for(register int k=head[x]; k; k=edge[k].next) //遍历所有与x相连的节点
if(!visit[edge[k].to]) { //若未被搜索
dfs(edge[k].to);
fa[edge[k].to]=x; //把x的孩子节点的fa重新设为x
}
for(register int k=qhead[x]; k; k=qedge[k].next) //搜索包含节点x的所有询问
if(visit[qedge[k].to]) { //如果另一节点已被搜索过
qedge[k].lca=find(qedge[k].to);//把另一节点的祖先设为这两个节点的最近公共祖先
if(k%2)//由于将每一组查询变为两组,所以2n-1和2n的结果是一样的
qedge[k+1].lca=qedge[k].lca;
else
qedge[k-1].lca=qedge[k].lca;
}
}
int main() {
read(n);
read(m);
read(p); //n:边数,m:查询次数,p:根的编号
for(register int i=1; i<n; ++i) {
read(x);
read(y); //每条边
add_edge(x,y);
add_edge(y,x);
}
for(register int i=1; i<=m; ++i) {
read(x);
read(y); //输入每次查询,考虑(u,v)时若查找到u但v未被查找,所以将(u,v)(v,u)全部记录
add_qedge(x,y);
add_qedge(y,x);
}
dfs(p); //进入以p为根节点的树的深搜
for(register int i=1; i<=m; ++i)
printf("%d\n",qedge[i*2].lca); //两者结果一样,只输出一组即可
return 0;
}

入门题目

CODEVS 2370 小机房的树

CODEVS 1036 商务旅行

METO CODE 223 拉力赛

ZOJ 3195 Design the city

【模板】Tarjian求LCA的更多相关文章

  1. tarjian求lca

    看了好多dalao的博客,就总结一下啦ovo tarjian算法很是神奇,它的作用是求lca.它是一种离线算法. 在线是指输入一个询问输出一个结果. 离线是将询问一次性输入,一起处理. tarjan它 ...

  2. 模板 树上求LCA 倍增和树链剖分

    //233 模板 LCA void dfs(int x,int f){ for(int i=0;i<E[x].size();i++){ int v = E[x][i]; if(v==f)cont ...

  3. [算法模板]倍增求LCA

    倍增LCA \(fa[a][i]\)代表a的第\(2^{i}\)个祖先. 主体思路是枚举二进制位,让两个查询节点跳到同一高度然后再向上跳相同高度找LCA. int fa[N][21], dep[N]; ...

  4. 倍增求lca模板

    倍增求lca模板 https://www.luogu.org/problem/show?pid=3379 #include<cstdio> #include<iostream> ...

  5. 倍增求lca(模板)

    定义LCA,最近公共祖先,是指一棵树上两个节点的深度最大的公共祖先.也可以理解为两个节点之间的路径上深度最小的点.我们这里用了倍增的方法求了LCA.我们的基本的思路就是,用dfs遍历求出所有点的深度. ...

  6. 求LCA最近公共祖先的在线倍增算法模板_C++

    倍增求 LCA 是在线的,而且比 ST 好写多了,理解起来比 ST 和 Tarjan 都容易,于是就自行脑补吧,代码写得容易看懂 关键理解 f[i][j] 表示 i 号节点的第 2j 个父亲,也就是往 ...

  7. LCA最近公共祖先模板(求树上任意两个节点的最短距离 || 求两个点的路进(有且只有唯一的一条))

    原理可以参考大神 LCA_Tarjan (离线) TarjanTarjan 算法求 LCA 的时间复杂度为 O(n+q) ,是一种离线算法,要用到并查集.(注:这里的复杂度其实应该不是 O(n+q)  ...

  8. 倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))

    倍增求\(LCA\) 倍增基础 从字面意思理解,倍增就是"成倍增长". 一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\ ...

  9. 树链剖分求LCA

    树链剖分中各种数组的作用: siz[]数组,用来保存以x为根的子树节点个数 top[]数组,用来保存当前节点的所在链的顶端节点 son[]数组,用来保存重儿子 dep[]数组,用来保存当前节点的深度 ...

随机推荐

  1. 自带的 print 函数居然会报错?

    前言 最近用 Python 写了几个简单的脚本来处理一些数据,因为只是简单功能所以我就直接使用 print 来打印日志. 任务运行时偶尔会出现一些异常: 因为我在不同地方都有打印日志,导致每次报错的地 ...

  2. 在写脚本时,在一开始(Shebang 之后)就加上这一句,或者它的缩略版: set -xeuo pipefail

    编写可靠 bash 脚本的一些技巧 腾讯技术工程 ​ 已认证的官方帐号   1,254 人赞同了该文章 写过很多 bash 脚本的人都知道,bash 的坑不是一般的多. 其实 bash 本身并不是一个 ...

  3. centos下查看网卡,主板,CPU,显卡,硬盘型号等硬件信息

    centos下查看网卡,主板,CPU,显卡,硬盘型号等硬件信息 rose_willow rose_willow 发布于 2016/06/16 11:32 字数 902 阅读 405 收藏 0 点赞 0 ...

  4. zabbix添加菜单栏

    1.更改字体(中文乱码多半是因为字体不支持中文) define('ZBX_GRAPH_FONT_NAME', 'DejaVuSans'); // font file name define('ZBX_ ...

  5. linux命令--使用fsck修复文件系统

    使用fsck修复文件系统错误 1.问题描述 服务器maint_samba 由于服务器maint_samba (debian操作系统)没有正常关机,在重新启动过程中/dev/sdb1出现文件系统错误,需 ...

  6. 抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext

    长话短说,本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext 引言 C#异步编程语法糖async/await,使开发者很容易就能编写异步代码. ...

  7. 浅析PriorityBlockingQueue优先级队列原理

    介绍 当你看本文时,需要具备以下知识点 二叉树.完全二叉树.二叉堆.二叉树的表示方法 如果上述内容不懂也没关系可以先看概念. PriorityBlockingQueue是一个无界的基于数组的优先级阻塞 ...

  8. 痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用. 我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目 ...

  9. VMware虚拟机CentOS磁盘扩容

    版本信息: VMware Workstation 15 Pro  15.5.2 build-15785246, CentOS7 原虚拟机默认20G,安装东西多了,磁盘空间不够用, docker mys ...

  10. 在Go语言项目中使用Zap日志库

    在Go语言项目中使用Zap日志库 本文先介绍了Go语言原生的日志库的使用,然后详细介绍了非常流行的Uber开源的zap日志库,同时介绍了如何搭配Lumberjack实现日志的切割和归档. 在Go语言项 ...