【一个蒟蒻的挣扎】LCA (倍增)
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
struct edge{
int next,to;
edge(){
}
edge(int a,int b){
next=a; to=b;
}
}E[];//建一个图……
int f[][],dep[],first[],tot;
int n,m,root;
void add_to_edge(int x,int y)
{
E[++t]=edge(first[x],y);
first[x]=t;
}//连边(无向图连两次哦)
void dfs(int x,int fa)
{
f[x][]=fa;
dep[x]=dep[fa]+;
//初始化 , 它的深度是它父亲的深度+1,x 往上倍增 2^0 层 是它的父亲
int k=ceil(log(dep[x])/log());//倍增上限
for (int i=; i<=k; i++)
{
f[x][i]=f[f[x][i-]][i-];
}//f数组存预处理的值,f[x][i]存的是x向上倍增
for (int i=first[x]; i; i=E[i].next)
{
int pos=E[i].to;
if (pos!=fa)//防止死循环,由于是存了两次所以E[i].to会连向它的父亲
dfs(pos,x);
}
}//预处理
int n,m,root;
void LCA()
{
if (dep[x]<dep[y]) swap(x,y);
int k1=dep[x]-dep[y];
int k2=ceil((log(n))/log());
for (int i=; i<=k2; i++)
{
if (k1&(<<i))
x=fa[x][i];
}//向上跳!!
if (x==y) return x;//两者在同一层并且相等那么x 就是它们的共同祖先
int k3=(log(dep[x])/log());
for (int i=k3; i>=; i--)
{
if (f[x][i]!=f[y][i])
{
x=f[x][i]; y=f[y][i];
}//倍增
}
return f[x][];
}
int main()
{
cin>>n>>m>>root;
for (int i=; i<=m; i++)
{
int x,y;
cin>>x>>y;
add_to_edge(x,y);
add_to_edge(y,s);
}
dfs(root,); }
还是济南集训的内容,让人头秃(不得不说两个老师讲了两遍我勉勉强强才搞懂一点点)
首先来看:
LCA的含义
Least Common Ancestors
LCA就是最近公共祖先,至于它的含义,我觉得例题写的看起来会更清楚,请看:

好的,明白了它的含义后,我们很容易想到朴素算法:
树上倍增算法
核心思想:
- 令F[x][n]表示x的2^n级祖先是谁.
- 所以:F[x][n] = F[F[x][n – 1]][n – 1].
- 对于两个点x, y.,求他们的LCA
- 先把x, y提到同一高度.(方便向上进行倍增)
- N从大到小枚举.(从高往低跳)
- 查询F[x][n], F[y][n]是不是相等(比较倍增后的祖先,防止误判)
- 如果是的话说明n太大了,把n改小点.(最近公共祖先的祖先一定是他们的共同祖先)
- 不是的话就说明n不大,可以把x, y上移.(这个很容易理解吧)

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = ;
const int maxe = ;
int n,m,root; struct line
{
int from,to;
line(){}//空构造函数 line p;
line(int A,int B){
//构造函数 line L=line(1,2);
from=A;to=B;
}
}edge[maxe];
//上面是新建一个树 int last[maxn],_next[maxe],e;
//last[x]表示以x为起点的最后一条边(的编号)
//_next[i]表示与第i条边起点相同的上一条边(的编号) void add_edge(int x,int y)
{
edge[++e]=line(x,y);
_next[e]=last[x];
last[x]=e;
}
//存边 int Fa[maxn][],Dep[maxn]; void dfs(int x,int fa)
{
int i,k,y;
Fa[x][]=fa;//当前节点x的父亲节点fa
Dep[x]=Dep[Fa[x][]]+; //x的深度是它父亲节点的深度+1
//记录当前节点的深度
k=ceil(log(Dep[x])/log()); //ceil函数是向上取整
//x往上倍增的上限
for(i=;i<=k;i++)Fa[x][i]=Fa[Fa[x][i-]][i-];
//倍增计算祖先 ,记录
for(int i=last[x];i;i=_next[i])//枚举与x相邻的边
{
int v=edge[i].to;
if(v!=fa)dfs(v,x);
}
} int LCA(int x,int y)
{
int i,k,s;
s=ceil(log(n)/log()); //该树倍增最大可能的上限
if(Dep[x]<Dep[y])swap(x,y); //交换x和y的值
/////////////x往上走k层,让x与y处于同一层 //////////
k=Dep[x]-Dep[y];
for(i=;i<=s;i++)
if(k&(<<i))x=Fa[x][i];
if(x==y)return x; //x==y时,x就是最近公共祖先
///////////////////////////////////////////////////
s=ceil(log(Dep[x])/log()); //计算向上倍增的上限
for(i=s;i>=;i--)
if(Fa[x][i]!=Fa[y][i]){ x=Fa[x][i]; y=Fa[y][i]; }
return Fa[x][];
} int main()
{
int i,j,k;
cin>>n>>m>>root;
for(i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);//它是树,也就是无向图,所以存两次边
}
dfs(root,);//预处理
for(i=;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",LCA(x,y));
} }
代码(带注释)
OK吗?
这里建议去练练板子,指路-> https://www.luogu.org/problem/P3379
(哇我居然可以写蓝题了哎!!可喜可贺)
感谢观看 ありがとうございます
【一个蒟蒻的挣扎】LCA (倍增)的更多相关文章
- 【一个蒟蒻的挣扎】最小生成树—Kruskal算法
济南集训第五天的东西,这篇可能有点讲不明白提前抱歉(我把笔记忘到别的地方了 最小生成树 概念:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的 ...
- 【一个蒟蒻的挣扎】单源最短路(Dijkstra)
赛前没啥时间好好解释了,还有三天2019CSP,大家加油啊!!! ヾ(◍°∇°◍)ノ゙ 背掉它就好啦!!! 我觉得我这一版打得还行就放上来了 #include<cstdio> #inclu ...
- noip2013Day2T3-华容道【一个蒟蒻的详细题解】
描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的 ...
- 一个蒟蒻对FFT的理解(蒟蒻也能看懂的FFT)
建议同学们先自学一下"复数(虚数)"的性质.运算等知识,不然看这篇文章有很大概率看不懂. 前言 作为一个典型的蒟蒻,别人的博客都看不懂,只好自己写一篇了. 膜拜机房大佬 HY 一. ...
- 这是一个蒟蒻的计划……QAQ
感觉像我这种拖拉的人很有可能是完成不了的,挂上来相当于监督我自己啦QWQ [学习计划] [√]1.去看Trie树!!! yyb学长的blog 2.KMP还有AC自动机 先贴两个链接在这里吧:KMP ...
- 一个蒟蒻的解题过程记录——洛谷P1003 铺地毯
这到题算是我“火线回归”后码的第一道题,病好了心情不错,发篇博客分享一下 目录: ·题目描述 ·题目分析 ·解题思路 ·代码实现 ·总结 ·题目描述: 为了准备一场特殊的颁奖典礼,组织者在会场的一片矩 ...
- 论一个蒟蒻的脑子里可以有多少坑(貌似咕了……目前更新保持在noip阶段)
就是错题整理了,其实也会把一些不该犯的失误整进来. 其实之前一直拖着不想写,直到某次模拟赛,看错了2道题,顺便爆了一道题的int(没错第一个点就会爆)之后爆零了,吓得我赶紧把这篇博客搞出来了..... ...
- 蒟蒻kc的垃圾数列
题目背景 在某教练的强迫之下,我一个蒟蒻居然出题了!!!出题了!!!(数据太水别找我qwq) 好的,JL说好的一题100快拿来 题目描述 首先,给你一个空的长度为n的序列(废话) 然后,你有一系列神奇 ...
- 算法描述》LCA两三事(蒟蒻向)
LCA是图论中常用的解决树形结构子问题的工具,这一问题一般需要用一个简短的子函数直接解决,但是这对于广大蒟蒻们仍然是一个不小的问题. LCA是指在树形结构中两点的最近公共祖先,对于这个问题,直接向上找 ...
随机推荐
- Java中 DecimalFormat 用法详解
我们经常要将数字进行格式化,比如取2位小数,这是最常见的.Java 提供DecimalFormat类,帮你用最快的速度将数字格式化为你需要的样子.下面是一个例子: import java.text.D ...
- #4 div1E Parentheses 括号匹配
E - Parentheses Time Limit:2000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu Subm ...
- R_Studio(癌症)以等宽类别值、自定义类别值、等频类别值(分为5类)
对“癌症.csv”中的肾细胞癌组织内微血管数进行连续属性的离散化处理 增加“微血管数分类1”属性,取值为等宽类别值(分为5类),增加“微血管数分类2”属性,取值为自定义类别值(0~40,41~60,6 ...
- vue自定义组件(vue.use(),install)+全局组件+局部组件
相信大家都用过element-ui.mintui.iview等诸如此类的组件库,具体用法请参考:https://www.cnblogs.com/wangtong111/p/11522520.html ...
- ImageIO类说明
最近的项目中遇到ImageIO,因此记录下这个类的用法 一.ImageIO: 这个类中的方法都是静态方法,可以用来进行简单的图片IO操作 1.读入的三种方法 public static Buffere ...
- C++入门经典-例3.6-判断某一年是否是闰年之复合表达式法
1:代码如下: // 3.6.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using ...
- pom文件中的dependencyManagement和dependencies的区别
dependencies 子项目中,自动继承父项目中的相关依赖 dependencyManagement 只是声明依赖,并不实现引入,因此子项目中需要显示的声明需要用的依赖.如果不在子项目中声明依赖, ...
- P1070道路游戏题解
日常吐槽 作为hin久hin久以前考试考到过的一道题窝一直咕咕咕到现在才想起来去做因为讲解都忘干净了然后自己重新考虑发现被卡了3天 题面 看到题目发现这题的dp状态似乎有点不是很明确? 我们来理一理题 ...
- scrollView 嵌套 listview 方式除了测量还有什么方法?
1.手动设置 ListView 高度经过测试发现,在 xml 中直接指定 ListView 的高度,是可以解决这个问题的,但是 ListView中的数据是可变的,实际高度还需要实际测量.于是手动代码设 ...
- 第三章 SpringCloud之Eureka-Client服务提供者
1.Eureka-Client简介 #################接下来开始程序啦########################## 1.pom.xml <?xml version=&qu ...