概况

LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。

实现过程
预处理:通过dfs遍历,记录每个节点到根节点的距离dist[u],深度d[u]
init()求出树上每个节点u的2^i祖先p[u][i]
求最近公共祖先,根据两个节点的的深度,如不同,向上调整深度大的节点,使得两个节点在同一层上,如果正好是祖先结束,否则,将两个节点同时上移,查询最近公共祖先。
代码:
#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int N=5e5+5;
int n,m,s;
int root;
int idx=1;
int ver[2*N],nex[2*N],head[2*N],dis[2*N],f[2*N][25];
queue<int>q;
int t; void add(int x,int y) {//邻接表建图
ver[++idx]=y;
nex[idx]=head[x];
head[x]=idx;
return ;
} void bfs() {//bfs会比dfs更加保险
q.push(root);
dis[root]=1;//根节点的深度为1
while(!q.empty()) {
int x=q.front();
q.pop();
for(int i=head[x]; i; i=nex[i]) {//向下一层搜索
int y=ver[i];
if(dis[y]) continue;//防止死循环
dis[y]=dis[x]+1;//深度更新
f[y][0]=x;//2^0=1,即为y的父结点
for(int j=1; j<=t; j++) {
f[y][j]=f[f[y][j-1]][j-1];//更新2^i个祖先
}
q.push(y);
}
}
return ;
} int lca(int x,int y) {
if(dis[x]<dis[y]){//严格规范dis[x]>dis[y]
swap(x,y);
}
for(int i=t; i>=0; i--) {
if(dis[f[x][i]]>=dis[y]) x=f[x][i];//使x和y的深度相同
}
if(x==y) return x;//已经相同,则直接返回x
for(int i=t; i>=0; i--) {
if(f[x][i]!=f[y][i]) {//如果第2^i个祖先不相同,说明还没有到最小公共祖先
x=f[x][i];
y=f[y][i];//更新x,y
}
}
return f[x][0];//返回x的父节点——即最小公共祖先
} int main() {
cin>>n;
t=(log(n)/log(2))+1;
for(int i=1; i<=n; i++) {
int a,b;
cin>>a>>b;
if(b==-1) root=a;
add(a,b);
add(b,a);
}
bfs();
cin>>m;
for(int i=1; i<=m; i++) {
int x,y;
cin>>x>>y;
if(lca(x,y)==x) cout<<1<<endl;
if(lca(x,y)==y) cout<<2<<endl;
if(lca(x,y)!=x&&lca(x,y)!=y) cout<<0<<endl;
}
// for(int i=1;i<=5;i++)cout<<i<<":"<<dis[i]<<endl;
return 0;
}

LCA算法——倍增的更多相关文章

  1. LCA算法倍增算法(洛谷3379模板题)

    倍增(爬树)算法,刚刚学习的算法.对每一个点的父节点,就记录他的2k的父亲. 题目为http://www.luogu.org/problem/show?pid=3379 第一步先记录每一个节点的深度用 ...

  2. LCA的倍增算法

    LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链 ...

  3. 关于LCA的倍增解法的笔记

    emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w 首先 何为LCA? LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主 ...

  4. [模板]LCA的倍增求法解析

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  5. 【图论】tarjan的离线LCA算法

    百度百科 Definition&Solution 对于求树上\(u\)和\(v\)两点的LCA,使用在线倍增可以做到\(O(nlogn)\)的复杂度.在NOIP这种毒瘤卡常比赛中,为了代码的效 ...

  6. LCA + 二分(倍增)

    两个最近的点u和v的最近的公共的祖先称为最近公共祖先(LCA).普通的LCA算法,每算一次LCA的时间复杂度为线性o(n); 这里讲LCA + 二分的方法.首先对于任意的节点v,利用其父节点的信息,可 ...

  7. LCA算法

    LCA算法: LCA(Least Common Ancestor),顾名思义,是指在一棵树中,距离两个点最近的两者的公共节点.也就是说,在两个点通往根的道路上,肯定会有公共的节点,我们就是要求找到公共 ...

  8. LCA算法解析-Tarjan&倍增&RMQ

    原文链接http://www.cnblogs.com/zhouzhendong/p/7256007.html UPD(2018-5-13) : 细节修改以及使用了Latex代码,公式更加美观.改的过程 ...

  9. LCA 算法(二)倍增

     介绍一种解决最近公共祖先的在线算法,倍增,它是建立在任意整数的二进制拆分之上.   代码:   //LCA:Doubly #include<cstdio> #define swap(a, ...

随机推荐

  1. rocketmq-cpp-client Visual Studio 2019 编译

    rocketmq-cpp-client Visual Studio 2019 编译 rocketmq-cpp-client 是rocketmq c++版本的 所以我们C++ 开发者使用此项目 构建 获 ...

  2. Vue.nextTick()的使用

    什么是Vue.nextTick()?? 定义:在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 所以就衍生出了这个获取更新后的DOM的Vue方法.所 ...

  3. 【Java基础】Java10 新特性

    Java10 新特性 局部变量类型推断 局部变量的显示类型声明,常常被认为是不必须的. 场景一:类实例化时.在声明一个变量时,总是习惯了敲打两次变量类型,第一次用于声明变量类型,第二次用于构造器. 场 ...

  4. 【MyBatis】MyBatis 多表操作

    MyBatis 多表操作 文章源码 一对一查询 需求:查询所有账户信息,关联查询下单用户信息. 注意:因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询.如果从用户 ...

  5. 天梯赛练习 L3-007 天梯地图 (30分) Dijkstra

    题目分析: 本题的题意比较清晰,就是有一个起点和一个终点,给出m条路径,可能是单向的可能是双向的,同时一条路有两个权重,分别是通过这条路需要的时间和这条路的路径长度,题目需要求出两条路径,一条是在最快 ...

  6. CentOS | python3.7安装指南

    前言: centos系统本身默认安装有python2.x,版本x根据不同版本系统有所不同 可通过 python --V 或 python --version 查看系统自带的python版本 有一些系统 ...

  7. RCE - Pikachu

    概述: 远程系统命令执行 一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口 比如我们常见的路由器.防火墙.入侵检测等设备的web管理界面上 一般会给用户提供一个ping操 ...

  8. JMS监听Oracle AQ

    该文档中,oracle版本为11g,jdk版本1.8,java项目为maven构建的springboot项目,springboot的版本为2.1.6,并使用了定时任务来做AQ监听的重连功能,解决由于外 ...

  9. ichartjs测试dome分享

    效果如下: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> ...

  10. 我为什么不鼓吹 WireGuard

    原文链接:https://fuckcloudnative.io/posts/why-not-wireguard/ 最近有一款新型 VPN 工具备受瞩目,相信很多人已经听说过了,没错就是 WireGua ...