tarjan算法_【朝夕的ACM笔记】树上问题-最近公共祖先-倍增算法
【朝夕的ACM笔记】目录与索引
最近公共祖先-倍增算法
一、基本概念
最近公共祖先问题:对于给定的一颗有根树,求其两个节点的最近公共祖先。
祖先:节点本身、节点的父亲、节点父亲的父亲……都是该节点的祖先。
公共祖先:两个节点共同的祖先。
最近公共祖先(Lowest Common Ancestor)即LCA:距离根最远的公共祖先(也是深度最大的公共祖先)。
*LCA的重要性质:
①若
②若
③两点的LCA必然在两点间的最短路上,事实上两点间的最短路就是从其中一点到LCA再到另一点。故
LCA的常见求法有:倍增算法、Tarjan算法、ST表算法、树链剖分四种。
本篇介绍第一种:倍增算法。
二、算法思想
2.1 朴素算法
在讲倍增算法前,我们先考虑一下暴力的朴素算法。
首先我们知道
所以我们可以先找到深度比较大的那个点,让它先往上跳,直到两点深度相同。
接着两点一起往上跳,什么时候汇聚在一点,那点就是最近公共祖先。
但是朴素算法的时间复杂度是比较大的,最坏情况下相当于
2.2 倍增算法
倍增算法是朴素算法的改进算法。对于每个点,我们先求出它向上的第
需要注意的是,向上跳跃时,我们应当先考虑跳大的步子。
什么意思呢?
比如说我们要求一个节点向上的第13个祖先。
那我们应该先跳8步,再跳4步,再跳1步。
对于预处理:
我们设
则显然
接下来从根节点向下DFS,每跑到一个点,都可以求出这个点的前
倍增的转移方程为
由于
对于求解LCA:
第一步先统一深度:
假设
然后一起向上跳,从大的步子开始,直到汇聚在同一点。
时间复杂度:
倍增算法预处理的时间复杂度是
三、参考代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
vector<int>e[500005];
int dep[500005];
int fa[500005][25];
int lg[500005];
void dfs(int s,int fn)//s表示当前点,fn是当前点的父亲节点
{fa[s][0]=fn;//第一个祖先就是本身dep[s]=dep[fn]+1;//记录点的深度for(int i=1;i<=lg[dep[s]]+1;i++)fa[s][i]=fa[fa[s][i-1]][i-1];//倍增转移for(int i=0;i<e[s].size();i++)if(e[s][i]!=fn) dfs(e[s][i],s);//向下遍历
}
void pre(int n)//快速预处理log2
{lg[1]=0,lg[2]=1;for(int i=3;i<=n;i++) lg[i]=lg[i/2]+1;
}
int lca(int x,int y)
{if(dep[x]<dep[y]) swap(x,y);//先保证x的深度大于等于ywhile(dep[x]>dep[y]) x=fa[x][lg[dep[x]-dep[y]]];//统一深度if(x==y) return x;//特判for(int i=lg[dep[x]];i>=0;i--)//从大步开始走if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];//一起往上跳return fa[x][0];
}
int read()//快读,增快读入速度
{int re=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0' && ch<='9'){re=re*10+ch-'0';ch=getchar();}return re;
}
int main()
{int n,m,s;//树的点数、询问次数、根节点n=read();m=read();s=read();for(int i=1;i<=n-1;i++){int x,y;x=read(),y=read();e[x].push_back(y);e[y].push_back(x);//树是无向图}pre(n);//预处理log2dfs(s,0);//dfs预处理fa数组for(int i=1;i<=m;i++){int a,b;a=read(),b=read();printf("%dn",lca(a,b));}return 0;
}
tarjan算法_【朝夕的ACM笔记】树上问题-最近公共祖先-倍增算法相关推荐
- 变种 背包问题_【朝夕的ACM笔记】动态规划-背包问题
[朝夕的ACM笔记]目录与索引 背包问题 一.0/1背包 1.1 问题描述 有 件物品和一个大小为 的背包,以及若干物品,每种物品只有一件,大小分别为 ,其价值分别为 .问题:将哪些物品装入背包,可使 ...
- 例题 - 最近公共祖先 - 离线算法
贴几篇LCA知识点的博客详解: CSDN - 青烟绕指柔!的博客 - 倍增算法 CSDN - Nekroz_的博客 CSDN - Dust_Heart的博客 CSDN - creatorx的博客 -T ...
- 树上问题(一)倍增算法求最近公共祖先
倍增算法求最近公共祖先 一.概述 在图论和计算机科学中,最近公共祖先 LCA(Least Common Ancestors)是指在一个树或者有向无环图中同时拥有v和w作为后代的最深的节点.在这里,我们 ...
- java python算法_用Python,Java和C ++示例解释的排序算法
java python算法 什么是排序算法? (What is a Sorting Algorithm?) Sorting algorithms are a set of instructions t ...
- 木桶排序算法_【生信常识】二代测序的比对算法浅析
前言 本来我只打算将孟大哥的视频内容做一个文字版的概述,然后孟大哥说,不如再加一个算法推导吧,然后我就开始看多一些东西,然后就想着把孟大哥视频里面大概提及然后没有仔细讲的部分做一些补充,完善整个体系的 ...
- dp聚类算法_【深度】基于残差分析的混合属性数据聚类算法
CAA 智慧起航,共创未来 聚类分析在医学.图像分割.生物学.电子商务.互联网等领域得到了广泛应用.在实际应用环境中,被聚类的数据通常含有数值属性和分类属性,例如医学检测报告不仅有血压.脉搏等数值属性 ...
- java代码隐藏面消除算法_计算机图形学—— 隐藏线和隐藏面的消除(消隐算法)...
一.概述 由于投影变换失去了深度信息,往往导致图形的二义性.要消除二义性,就必须在绘制时消除被遮挡的不可见的线或面,习惯上称作消除隐藏线和隐藏面(或可见线判定.可见面判定),或简称为消隐.经过消隐得到 ...
- sha256算法_腾讯云提供免费证书已支持使用ECC算法 大幅度节省证书流量
目前大多数网站使用的都是基于RSA非对称加密算法签发的数字证书,而在部署加密协议后服务器开销亦会增加. 对大型网站而言如果有能够降低服务器开销的方法那自然也得用上,所以现在很多网站也开始使用ECC数字 ...
- sift算法_论文和专利笔记:翻拍检测算法
数码翻拍图像取证算法(论文) 方法一:噪声分析 通过小波变换(具体的方法包括可分离的散 小 波 变 换 ( Separable 2-D DWT),二维双树离散实数小波变换 ( Real 2-D dua ...
最新文章
- 嘿,老李,又在写 BUG 呢?
- Android 使用ViewPager 做的半吊子的图片轮播
- LuoguP3959 宝藏 题解
- 在.NET 2.0正式版中开发无刷新页面
- 收留我接入云信,打造陌生人旅行社交
- KMP算法理解(转)
- 3.12 12!配对
- 50种Java编程技巧,越早知道越好!(建议收藏)
- LoadRunner常见错误代码解决方案
- 校招真题练习009 配比(京东)
- 通过SecureCRT工具从远程Linux服务器下载文件到本地Windows
- 计算机网络 8 报文交换和分组交换2
- WinPE (老毛桃最终修改版) V09.11 硬盘安装操作系统详细图解
- 懂得,是生命中最美的缘
- EndNote添加其他参考文献格式教程
- 沪牌学院-沪拍拍课堂4: 实拍前的演练
- [ZT]金融衍生品的重大危害性——兼谈3.27国债风暴
- 6500元都不到?战神Z8-DA5NP配置强悍,神船的性价比又回来了
- iOS - 微信分享无法显示好友列表
- 基于单片机的电流检测仿真设计(#0041)
热门文章
- 齐博地方门户系统v5_社区团购小程序哪个好?-小猪V5社区团购系统,社区团购系统,社区团购小程序,专注社区团购系统研发...
- 新思路等级考二级c语言题答案,2017计算机二级C语言考试强化习题及答案
- 机器学习算法_机器学习算法中分类知识总结!
- 18python入门到精通_《Python从入门到精通(60课)》18 序列类型之元组
- 学mysql是学指令吗_学习Mysql (二) 常用指令
- Django中提供了6种缓存方式,你会几种?
- Python基础教程:函数的可变参数
- Python基础教程:条件语句的七种写法
- python中的及||
- 四步解读python生成器