【模板】最近公共祖先(LCA)

题意

  • 给一个树,然后多次询问(a,b)的LCA

模板(主要参考一些大佬的模板)

#include<bits/stdc++.h>
//自己的2点:树的邻接链表(静态)表示; lca 的倍增算法
//优化 log[]
const int maxn=500010;
int N,M,S;//S根节点标号
int head[maxn];//head[i]=k 以i为起点的第一条边是edge[k]
int dep[maxn],dp[maxn][21];//dp[i][j] i向上走2^j
int lg[maxn];//(log2(i)+1) struct edge{
int v,next;
};
edge egs[maxn<<1];
int k=0;
void getlg(){
for(int i=1;i<=n;i++){
lg[i]=lg[i-1]+((1<<lg[i-1])==i);
}
}
void add(int a,int b){
//加入边a,b
egs[k].v=b;
egs[k].next=head[a];
head[a]=k++;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
//printf("db: u %d fa %d dep %d %d\n",u,fa,dep[u],dep[fa]);
dp[u][0]=fa;
for(int i=1;(1<<i)<=dep[u];i++){
dp[u][i]=dp[dp[u][i-1]][i-1];
}
int k;
for(k=head[u];k!=-1;k=egs[k].next){
if(egs[k].v!=fa) dfs(egs[k].v,u);
} }
int lca(int a,int b){
if(dep[a]<dep[b]) std::swap(a,b);
//dep[a]>=dep[b] a 向上走
for(int j=20;j>=0;j--){
if(dep[a]-(1<<j)>=dep[b]){
a=dp[a][j];
}
}
if(a==b) return a;
//a,b同时向上走
for(int i=20;i>=0;i--){
if(dp[a][i]!=dp[b][i]){
a=dp[a][i];
b=dp[b][i];
}
}
return dp[a][0];
} int main(){
scanf("%d %d %d",&N,&M,&S);
memset(head,-1,sizeof(head));
memset(dep,0,sizeof(dep));
memset(dp,0,sizeof(dp));
for(int i=1;i<N;i++){
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
add(b,a);
} dfs(S,0);
/*
for(int i=0;i<=N;i++){
printf("db: %d %d\n",i,dep[i]);
}
*/
int x,y;
for(int i=1;i<=M;i++){
scanf("%d %d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0; }

加了lg[]数组优化的(略微快一点)

#include<bits/stdc++.h>
//自己的2点:树的邻接链表(静态)表示; lca 的倍增算法
//优化 log[]
const int maxn=500010;
int N,M,S;//S根节点标号
int head[maxn];//head[i]=k 以i为起点的第一条边是edge[k]
int dep[maxn],dp[maxn][21];//dp[i][j] i向上走2^j
int lg[maxn];//(log2(i)+1) struct edge{
int v,next;
};
edge egs[maxn<<1];
int k=0;
void getlg(){
for(int i=1;i<=N;i++){
lg[i]=lg[i-1]+((1<<lg[i-1])==i);
}
}
void add(int a,int b){
//加入边a,b
egs[k].v=b;
egs[k].next=head[a];
head[a]=k++;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
//printf("db: u %d fa %d dep %d %d\n",u,fa,dep[u],dep[fa]);
dp[u][0]=fa;
for(int i=1;i<=(lg[dep[u]]-1);i++){
dp[u][i]=dp[dp[u][i-1]][i-1];
}
int k;
for(k=head[u];k!=-1;k=egs[k].next){
if(egs[k].v!=fa) dfs(egs[k].v,u);
} }
int lca(int a,int b){
if(dep[a]<dep[b]) std::swap(a,b);
//dep[a]>=dep[b] a 向上走
while(dep[a]>dep[b]){
a=dp[a][lg[dep[a]-dep[b]]-1];
}
if(a==b) return a;
//a,b同时向上走
for(int i=(lg[dep[a]]-1);i>=0;){
if(dp[a][i]!=dp[b][i]){
a=dp[a][i];
b=dp[b][i];
i=lg[dep[a]];
}
else i--;
}
return dp[a][0];
} int main(){
scanf("%d %d %d",&N,&M,&S);
memset(head,-1,sizeof(head));
memset(dep,0,sizeof(dep));
memset(dp,0,sizeof(dp));
getlg();
for(int i=1;i<N;i++){
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
add(b,a);
} dfs(S,0);
/*
for(int i=0;i<=N;i++){
printf("db: %d %d\n",i,dep[i]);
}
*/
int x,y;
for(int i=1;i<=M;i++){
scanf("%d %d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0; }

值得注意的问题

  • 初始化的位置
  • 树的邻接链表表示(真的比较省内存而且好用)
  • lca的倍增算法(还可以求树上两点距离)

luogo p3379 【模板】最近公共祖先(LCA)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. 【洛谷 p3379】模板-最近公共祖先(图论--倍增算法求LCA)

    题目:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 解法:倍增. 1 #include<cstdio> 2 #include<cstdlib> 3 #include ...

  7. 最近公共祖先(LCA)模板

    以下转自:https://www.cnblogs.com/JVxie/p/4854719.html 首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖 ...

  8. HDU 2586 How far away ?(LCA模板 近期公共祖先啊)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...

  9. luogu3379 【模板】最近公共祖先(LCA) 倍增法

    题目大意:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 整体步骤:1.使两个点深度相同:2.使两个点相同. 这两个步骤都可用倍增法进行优化.定义每个节点的Elder[i]为该节点的2^k( ...

  10. 最近公共祖先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 ...

随机推荐

  1. 洛谷P3960 列队 Splay

    其实思路并不算太难,就是代码量相对较大. 我们将一次离队转换为一次删除和两次加入,这样就可以保证空间是动态分配的,最大也不会暴空间. 说实话写之前感觉会很恶心,但是代码量就还好吧,有些细节需要特殊注意 ...

  2. 《Python数据分析与挖掘实战》-第四章-数据预处理

    点我看原版

  3. VS2013 opencv 无法删除“继承的值”问题解决方案

    http://www.360doc.com/content/15/0103/14/110467_437739376.shtml 解决方案: (1)视图——其他窗口——属性管理器. 注意:是”属性管理器 ...

  4. bootstrapvalidator使用,重置校验

    1.html页面需要注意的是验证字段需要用form-group包裹.需要引用相应的css和js. <form id="jobForm" role="form&quo ...

  5. linux系统时间与网络时间不同步

    在解决问题之前,我们首先来了解下面几个知识点: 1. date命令: #date 显示系统时间 2.hwclock命令   (即hardwareclock系统硬件时间) #hwclock 显示硬件时间 ...

  6. 【JavaScript框架封装】使用Prototype给Array,String,Function对象的方法扩充

    /* * @Author: 我爱科技论坛* @Time: 20180705 * @Desc: 实现一个类似于JQuery功能的框架* V 1.0: 实现了基础框架.事件框架.CSS框架.属性框架.内容 ...

  7. [tyvj-1391]走廊泼水节 最小生成树

    做克鲁斯卡尔的时候维护一个并查集即可. #include <iostream> #include <cstdio> #include <cstring> #incl ...

  8. uni-app 之验证码

    手机APP---验证码 最近公司在开发手机APP,app避不可免的就是登录了,emmmm 登录验证码那必须的是有的,我们公司发给我们的图片是酱紫的~~ 这个要求大家应该都能看懂,做这个手机号啊,验证码 ...

  9. Ubuntu14.04 Anaconda

    我虚拟机Ubuntu14.04上的Python已经存在了两个版本,一个是python 2.7,一个是Python 3.4.想在它上面安装Anaconda,但又有所顾虑.我先想到的是,先卸载Ubuntu ...

  10. 基于vue的可视化编辑器

     https://github.com/jaweii/Vue-Layout  https://github.com/L-Chris/vue-design  https://github.com/fir ...