luogo p3379 【模板】最近公共祖先(LCA)
【模板】最近公共祖先(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)的更多相关文章
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 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 之间所有路径中深度最小的节 点,所 ...
- 【洛谷 p3379】模板-最近公共祖先(图论--倍增算法求LCA)
题目:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 解法:倍增. 1 #include<cstdio> 2 #include<cstdlib> 3 #include ...
- 最近公共祖先(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 ...
随机推荐
- navicat Premium远程链接mysql报错
1,报错1057,原来是没有远程权限连接mysql 2.打开my.ini文件,添加skip-grant-tables跳过验证 3.添加到path环境变量,前面是英文下的分号 4.切换到cmd,输入my ...
- 00074_Array类
1.Array类的概述 此类包含用来操作数组(比如排序和搜索)的各种方法.需要注意,如果指定数组引用为 null,则访问此类中的方法都会抛出空指针异常NullPointerException. 2.常 ...
- CodeForcesGym 100641B A Cure for the Common Code
A Cure for the Common Code Time Limit: 3000ms Memory Limit: 262144KB This problem will be judged on ...
- mysql在windows下主从同步配置
mysql主从同步: 1.为什么要主从同步? 在Web应用系统中,数据库性能是导致系统性能瓶颈最主要的原因之一.尤其是在大规模系统中,数据库集群已经成为必备的配置之一.集群的好处主要有:查询负载. ...
- 工具-VS2015前端开发工具简介
每个涉及的工具库都给出了入门介绍.基本概念,以及在VS和ASP.NET中的用法.这个白皮书完全就是一个非常难得的前端开发入门手册. 具体涉及到的工具库有: 流行的JS任务执行器:Grunt和Gulp. ...
- BA-siemens-symaro传感器简介
1 传感器的原理 传感器.控制器.执行机构是构成控制系统 3 个要素,传感器的作 用一般用来测量工艺参数,提供给控制器或显示仪表,实现工艺过程的 监测或控制.传感器的类型是按测量参数不同分类的,主要分 ...
- HDU——T1231 最大连续子序列
http://acm.hdu.edu.cn/showproblem.php?pid=1231 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连 ...
- 【C/C++学院】0724-堆栈简单介绍/静态区/内存完毕篇/多线程
[送给在路上的程序猿] 对于一个开发人员而言,可以胜任系统中随意一个模块的开发是其核心价值的体现. 对于一个架构师而言,掌握各种语言的优势并能够运用到系统中.由此简化系统的开发.是其架构生涯的第一步. ...
- Chisel Tutorial(一)——Chisel介绍
Chisel是由伯克利大学公布的一种开源硬件构建语言,建立在Scala语言之上,是Scala特定领域语言的一个应用,具有高度參数化的生成器(highly parameterized generator ...
- 5.文件I/O
1 C标准函数与系统函数的区别 文件的结构体: 1.1 I/O缓冲区 每一个FILE文件流都有一个缓冲区buffer,默认大小8192Byte. 1.2 效率 文件缓冲区会降低效率.这里提供缓冲区主要 ...