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 ...
随机推荐
- Vue学习之路第十六篇:车型列表的添加、删除与检索项目
又到了大家最喜欢的项目练习阶段,学以致用,今天我们要用前几篇的学习内容实现列表的添加与删除. 学前准备: ①:JavaScript中的splice(index,i)方法:从已知数组的index下标开始 ...
- vue 动态添加路由 require.context()
之前的写法 'use strict' import Vue from 'vue' import MessageBroadcast from 'page/MessageBroadcast' import ...
- 纯css3实现箭头、关闭按钮旋转效果
说起css3的旋转效果,那就要说为什么不用js去实现,CSS3的动画效果,能够减少对JavaScript和Flash文件的HTTP请求这是原因之一.但是css3可能要求浏览器执行很多的工作来完成这个动 ...
- 修改linux新建账户时的过期时间
#!/bin/bash cat << EOF >> /etc/login.defs PASS_MAX_DAYS 90 EOF
- MySQL 获取无限级某级的全路径
传递参数:文件夹ID DROP FUNCTION IF EXISTS RecursionFolderFullPath; CREATE FUNCTION RecursionFolderFullPath( ...
- 警告: The APR based Apache Tomcat Native library failed to load.
警告: The APR based Apache Tomcat Native library failed to load. The error reported was [C:\apache-tom ...
- UVA11827 Maximum GCD
/* UVA11827 Maximum GCD https://vjudge.net/contest/153365#problem/V 数论 gcd 水题,然而读入比较坑 * */ #include ...
- Java&Xml教程(十一)JAXB实现XML与Java对象转换
JAXB是Java Architecture for XML Binding的缩写,用于在Java类与XML之间建立映射,可以帮助开发人员非常方便的將XML和Java对象进行相互转换. 本文以一个简单 ...
- UVA 10196 Morning Walk(欧拉回路)
Problem H Morning Walk Time Limit 3 Seconds Kamalis a Motashotaguy. He has got a new job in Chittago ...
- SOA概念具体解释
1.概述 1.1基本定义 SOA(Service-Oriented Architecture)既面向服务的体系结构,是一个组件模型.它将应用程序猿的不同功能可是(称为服务)通过定义良好的接口联系起来. ...