【模板】最近公共祖先(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. java.util.Date日期类通过java语句转换成Sql(这里测试用的是oracle)语句可直接插入(如:insert into)的日期类型

    public void add(Emp emp) throws Exception{ QueryRunner runner = new QueryRunner(JdbcUtil.getDataSour ...

  2. Connection refused (SQL: select * from information_s chema.tables where table_schema = apidemo and table_name = migrations)

    LARAVEL 执行: $ php artisan migrate 报错 ,把 .env文件里的 DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306 换成 ...

  3. BZOJ 3144 [HNOI2013]切糕 (最大流+巧妙的建图)

    题面:洛谷传送门 BZOJ传送门 最大流神题 把点权转化为边权,切糕里每个点$(i,j,k)$向$(i,j,k+1)$连一条流量为$v(i,j,k)$的边 源点$S$向第$1$层的点连边,第$R+1$ ...

  4. win主机ping不通linux的IP

    1.虚拟机的中的linux系统设置成桥接模式 2.点击虚拟机的编辑选择虚拟网络编辑器 3.点击更改设置 4点击还原默认设置即可

  5. nginx启动、关闭与重启命令

    nginx启动 1.启动nginx:./nginx  2.关闭nginx:./nginx  -s  stop 3.重启nginx:./nginx -s reload

  6. fun(int **p)的使用

    #include <iostream>using namespace std;void fun(int **p){ cout << p[0][0] << endl; ...

  7. CentOS 7下搭建高可用集群

    一 .安装集群软件 必须软件pcs,pacemaker,corosync,fence-agents-all,如果需要配置相关服务,也要安装对应的软件. 二.配置防火墙1.禁止防火墙和selinux# ...

  8. Jdk和Cglib 的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的代理类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  9. pythonWeb -- Django开发- Admin

    [第一次使用Admin 要创建超级用户账号] 1.\ python manage.py createsuperuser You have 1 unapplied migration(s). Your ...

  10. POJ 2191

    只会打表 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring ...