[模板] 最近公共祖先/lca
简介
最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点.
定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * (r,fa(lca))\). (树上差分)
求法
tarjan
离线算法, 总时间 \(O(n+q)\). (q表示询问次数)
//利用前向星存储询问
struct te{int t,pr,lca;}edge[1000050],qedge[1000050];
int head[500050],pe=1,qhead[500050],pq=1;
void adde(int f,int t){
edge[++pe].t=t;
edge[pe].pr=head[f];
head[f]=pe;
}
void addq(int f,int t){
qedge[++pq].t=t;
qedge[pq].pr=qhead[f];
qhead[f]=pq;
}
//并查集
int fa[500050];
int find(int p){return p==fa[p]?p:fa[p]=find(fa[p]);}
void merge(int l,int r){fa[r]=l;}//merge r to l
//tarjan
int vi[500050];
void tar(int p){
vi[p]=1;
for(int i=head[p];i;i=edge[i].pr){
if(vi[edge[i].t])continue;
tar(edge[i].t);
merge(p,edge[i].t);
}
for(int i=qhead[p];i;i=qedge[i].pr)
if(vi[qedge[i].t])
qedge[i].lca=qedge[i^1].lca=find(qedge[i].t);
}
倍增
\(O(n\log n)\)预处理, \(O(\log n)\) 查询, \(O(n\log n)\)空间. 由于利用结合律, 可以维护一些链上信息. 可以动态维护.
int fa[nsz][20],dep[nsz]{-1};
//动态维护
void addfa(int p,int f){
dep[p]=dep[f]+1;
fa[p][0]=f;
rep(i,1,18)fa[p][i]=fa[fa[p][i-1]][i-1];
}
//静态
void init(){
dfs(1,0); //get fa[i][0]
rep(i,1,18)rep(j,1,n)fa[j][i]=fa[fa[j][i-1]][i-1];
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
repdo(i,18,0)if(dep[fa[a][i]]>=dep[b])a=fa[a][i];
if(a==b)return a;
repdo(i,18,0)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
欧拉序+rmq
\(O(n\log n)\)预处理, \(O(1)\) 查询, \(O(n\log n)\)空间.
int l2n[nsz*3+50];
int eul[nsz*3],cnt=0,vis[nsz],d[nsz];
int stt[nsz*3][21];
void dfs(int u,int fa){
eul[++cnt]=u;
if(vis[u]==0)vis[u]=cnt,d[u]=d[fa]+1;
for(int i=hd[u],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){
if(v==fa)continue;
dfs(v,u);
eul[++cnt]=u;
}
}
int dmin(int a,int b){return d[a]<=d[b]?a:b;}
void rmq(){
rep(i,1,cnt)stt[i][0]=eul[i];
rep(j,1,l2n[pe]){
rep(i,1,pe+1-(1<<j)){
stt[i][j]=dmin(stt[i][j-1],stt[i+(1<<(j-1))][j-1]);
}
}
}
int stqu(int a,int b){
int l=l2n[b-a+1];
return dmin(stt[a][l],stt[b-(1<<l)+1][l]);
}
void eulinit(){
int l=0;
rep(i,1,n*3){
if(i==(1<<(l+1)))++l;
l2n[i]=l;
}
dfs(s,0);
rmq();
}
int lca(int a,int b){
int x=vis[a],y=vis[b];
if(x>y)swap(x,y);
return stqu(x,y);
}
树链剖分
\(O(n)\)预处理, \(O(\log n)\) 查询, \(O(n)\)空间. 由于利用结合律, 可以维护一些链上信息.
int dep[nsz],sz[nsz],son[nsz],fa[nsz],top[nsz];
void dfs1(int p,int f){
sz[p]=1,dep[p]=dep[f]+1,fa[p]=f;
for(int i=hd[p],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){
if(v==f)continue;
dfs1(v,p);
sz[p]+=sz[v];
if(son[p]==0||sz[son[p]]<sz[v])son[p]=v;
}
}
void dfs2(int p,int tv){
top[p]=tv;
if(son[p])dfs2(son[p],tv);
for(int i=hd[p],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){
if(v==fa[p]||v==son[p])continue;
dfs2(v,v);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]>=dep[top[y]])x=fa[top[x]];
else y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
[模板] 最近公共祖先/lca的更多相关文章
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)
POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- 最近公共祖先(LCA)模板
以下转自:https://www.cnblogs.com/JVxie/p/4854719.html 首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖 ...
- HDU 2586 How far away ?(LCA模板 近期公共祖先啊)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...
- luogu3379 【模板】最近公共祖先(LCA) 倍增法
题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...
- 最近公共祖先lca模板
void dfs(int x,int root){//预处理fa和dep数组 fa[x][0]=root; dep[x]=dep[root]+1; for(int i=1;(1<<i)&l ...
- 【洛谷 p3379】模板-最近公共祖先(图论--倍增算法求LCA)
题目:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 解法:倍增. 1 #include<cstdio> 2 #include<cstdlib> 3 #include ...
随机推荐
- Java设计模式之【工厂模式】(简单工厂模式,工厂方法模式,抽象工厂模式)
Java设计模式之[工厂模式](简单工厂模式,工厂方法模式,抽象工厂模式) 工厂模式出现的原因 在java中,创建一个对象最简单的方法就是使用new关键字.但在一些复杂的业务逻辑中,创建一个对象不只需 ...
- java开发环境配置——IntelliJ IDEA
关于开发工具,之前是用eclipse,后来用了一段时间idea后,发现idea比eclipse好用太多了,所以推荐大家用idea 官网下载地址:https://www.jetbrains.com/id ...
- po编程——自动化测试面试必问
先来看一个在腾讯课堂首页搜索机构的操作步骤: 1:首先打开腾讯课堂的首页:https://ke.qq.com 2:点击课程或机构的下拉选择图标 3:选择机构 4:在搜索框输入要搜索的机构名称 5:点击 ...
- C#基础第五天
public struct Person { public string _name; public Gender _sex; public int _age; } public enum Gende ...
- MPP架构海量数据分析仓库——Greenplum介绍
一.Greenplum背景 时间回到2002年,互联网行业经过近10年的发展,数据量正处于快速增长期: 1.传统的主机计算模式在海量数据面前,除了造价昂贵外,在CPU计算和IO吞吐上不能满足海量数据的 ...
- LivePhoto开发,你要知道的知识点
前言 Apple从iPhone6s开始支持Live Photo.Live Photo 会录下拍照前后 1.5 秒所发生的一切,因此用户获得的不仅仅是一张精美照片,还有拍照前后时刻的动作和声音.具体的操 ...
- 英语口语练习系列-C09-常用动词
<先秦 · 关雎> 关关雎鸠,在河之洲.窈窕淑女,君子好逑. 参差荇菜,左右流之.窈窕淑女,寤寐求之. 求之不得,寤寐思服.悠哉悠哉,辗转反侧. 参差荇菜,左右采之.窈窕淑女,琴瑟友之. ...
- oc中的委托模式
通过一个例子来理解委托模式 首先定义个协议 协议(protocol) :它可以声明一些必须实现的方法和选择实现的方法 (在java中称为接口) // // StudentDelegate.h // ...
- java程序启动 环境属性的获取
System.getProperties().list(System.out); 如果要获取某一个属性,例如常见的“操作系统” 则 System.getProperty("os.name& ...
- Koa 框架介绍
Node.js 是一个异步的世界,官方 API 支持的都是 callback 形式的异步编程模型,这 会带来许多问题,例如:callback 嵌套问题 ,异步函数中可能同步调用 callback 返回 ...