倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))
倍增求\(LCA\)
倍增基础
从字面意思理解,倍增就是“成倍增长”。
一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\)的区间值。在这些预处理结果的基础上,我们可以进一步求出任意长度区间的答案。
比如区间最值问题\((RMQ)\)就可以使用倍增解决。对于每个起始点,预处理长度为\(2^n\)的区间最值。之后每段区间都可以以此求出,如:
\(f(1,7)=\max(f(1,4),f(3,7))\)
以上是最简单的一个举例。在计算机中,二进制的思想运用广泛。它能将复杂度中\(n\)因子化为\(log_2n\),还可以使用位运算进行常数优化。
\(LCA\)
LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。——百度百科
定义很好理解。朴素的做法是预处理深度,将深度大的向上跳,再一起向上跳直到相遇。复杂度不好算,但绝对T飞。
注意到当两点相遇后,再如何跳都在同一个点上。所以就相当于\(LCA\)下不同,\(LCA\)上相同。这具有单调性,考虑二分。此处要对每一个点存储\(2^n\)级祖先,方法是预处理时递推。
我们记点i的\(2^k\)级祖先为\(fa[i][k]\)。
求解\(LCA\)的过程分为两步:一是提升到同一高度,二是同时向上跳。从最大的\(fa[x][log_2(depth[x])]\)开始逐次减半,相同则不跳,不同则跳。最终会到达\(LCA\)的下方。此时返回其中一个点的父亲,算法结束。
另外,预处理\(log_2\)的结果可以优化常数。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int n,m,s,x,y;
const int MAXN=500005;
struct edge
{
int to,next;
}tree[MAXN*2];
int depth[MAXN],lg2[MAXN],head[MAXN],fa[MAXN][25],eg,temp;
int add(int from,int to)
{
tree[++eg].to=to;
tree[eg].next=head[from];
head[from]=eg;
}
int get_depth(int node,int father)//当前点和父亲
{
depth[node]=depth[father]+1;
fa[node][0]=father;
for(int i=1;i<=lg2[depth[node]]-1;i++)
fa[node][i]=fa[fa[node][i-1]][i-1];//node的2^i级父亲等于它的 2^(i-1)级父亲的2^(i-1)级父亲
for(int i=head[node];i;i=tree[i].next)
if(tree[i].to!=father) get_depth(tree[i].to,node);
}
inline int LCA(int x,int y)
{
if(depth[x]<depth[y])
temp=x,x=y,y=temp;//确保x更深,便于处理
while(depth[x]>depth[y])
x=fa[x][lg2[depth[x]-depth[y]]-1];//跳到相同高度
if(x==y) return x;
for(int i=lg2[depth[x]]-1;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];//注意返回的不是x,是x的父亲
}
int main()
{
scanf("%d %d %d",&n,&m,&s);
for(int i=1;i<=n-1;i++)
scanf("%d %d",&x,&y),add(x,y),add(y,x);//建树
for(int i=1;i<=MAXN;i++)
lg2[i]=lg2[i-1]+(1<<lg2[i-1]==i);//预处理log
get_depth(s,0);//预处理2^n级父亲,深度等信息
for(int i=1;i<=m;i++)
scanf("%d %d",&x,&y),printf("%d\n",LCA(x,y));
return 0;
}
倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))的更多相关文章
- 快速沃尔什变换(FWT)学习笔记 + 洛谷P4717 [模板]
FWT求解的是一类问题:\( a[i] = \sum\limits_{j\bigoplus k=i}^{} b[j]*c[k] \) 其中,\( \bigoplus \) 可以是 or,and,xor ...
- [模板] 最近公共祖先/lca
简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...
- 斜率优化dp学习笔记 洛谷P3915[HNOI2008]玩具装箱toy
本文为原创??? 作者写这篇文章的时候刚刚初一毕业…… 如有错误请各位大佬指正 从例题入手 洛谷P3915[HNOI2008]玩具装箱toy Step0:读题 Q:暴力? 如果您学习过dp 不难推出d ...
- 边带权并查集 学习笔记 & 洛谷P1196 [NOI2002] 银河英雄传说 题解
花了2h总算把边带权并查集整明白了qaq 1.边带权并查集的用途 众所周知,并查集擅长维护与可传递关系有关的信息.然而我们有时会发现并查集所维护的信息不够用,这时"边带权并查集"就 ...
- STL Stack(栈)学习笔记 + 洛谷 P1449 后缀表达式
稍微看了看刘汝佳的白皮书,“实用主义”的STL实在是香到我了,而且在实验室大佬的推荐下我开始了stl的学习. 每篇附带一个题目方便理解,那行,直接开始. 毕竟是实用主义,所以就按照给的题目的例子来理解 ...
- STL Queue(队列)学习笔记 + 洛谷 P1540 机器翻译
队(Queue) 队简单来说就是一个先进先出的“栈”,但是不同于标准“栈”的先进后出. 基本操作: push(x) 将x压入队列的末端 pop() 弹出队列的第一个元素(队顶元素),注意此函数并不返回 ...
- leetcood学习笔记-235-二叉搜索树的最近公共祖先
题目描述: 利用二叉搜索树的特点,如果p.q的值都小于root,说明p q 肯定在root的左子树中:如果p q都大于root,说明肯定在root的右子树中,如果一个在左一个在右 则说明此时的root ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 【lhyaaa】最近公共祖先LCA——倍增!!!
高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...
- Django 学习笔记(五)模板标签
关于Django模板标签官方网址https://docs.djangoproject.com/en/1.11/ref/templates/builtins/ 1.IF标签 Hello World/vi ...
随机推荐
- new和delete必须成对出现吗?【网上集合贴+个人总结】
new和delete必须成对出现吗?[网上集合贴+个人总结] 1.从内存泄露与否的角度考虑 new 和 delete不一定要成对出現.理论上是這樣的.但是从习惯上來說,new delete成對出現是一 ...
- 记录一次PHP项目报502的问题
问题描述 最近有台服务器偶尔会报502错误,虽然量不多,每天就几十个,但是也必须得找到原因,避免让小问题变成大问题. 排查过程 502错误的原因,一般是对用户访问请求的响应超时造成的,一开始以为是请求 ...
- Qt5图形视图框架的“俄罗斯方块”(使用了QGraphicsView)
Qt5 图形视图框架QGraphicsView 1.图形视图框架包含三大类:场景类(QGraphicsScene),视图类(QGraphicsView),图元类(QGraphicsItem): 2.对 ...
- SPOJ1421_Goods_循环节
题意:1-n的一个排列,两两互换,每个位置每天只能做一次交换,问最多几天能交换成1-n,并且输出交换步骤. 解法:把该置换中所有的循环节找出,各循环节之间的交换是并行的,两两不相关,每天只需在循环节内 ...
- asp.net core系列 66 Dapper介绍--Micro-ORM
一.概述 目前对于.net的数据访问ORM工具很多,EF和EF Core是一个重量级的框架.最近在搭建新的项目架构,来学习一下轻量级的数据访问ORM工具Dapper.Dapper支持SQL Serve ...
- 记录 nginx和php安装完后的URL重写,访问空白和隐藏index.php文件的操作方法
sudo cd /etc/nginx/; sudo vi fastcgi_params; 1.URL重写 如果你的url参数不是用?xxx传递,而是自定义的,比如用/xx/xx/xx的方式传递,那么在 ...
- Laravel --- 如何较优雅的使用公用函数
一.创建公用文件 App/Helpers/CommonHelper.php 二.创建Provider php artisan make:provider HelperServiceProvider C ...
- C++程序设计1(侯捷video 1-6)
一.头文件的防御式声明(video2) #ifndef __COMPLEX__ #define __COMPLEX__ //内容 #endif 二.初步感受模板(video2) 定义的时候: //复数 ...
- spring cloud 系列第7篇 —— sleuth+zipkin 服务链路追踪 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.简介 在微服务架构中,几乎每一个前端的请求都会经过多个服务单元协调来提 ...
- memecached存放session数据
memcached存放session 1.session数据需要频繁调用. 2.session数据不需要永久性的保存在服务端. 3.在集群中,可以将session存放在memcached中或者是在数据 ...