【一个蒟蒻的挣扎】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是指在树形结构中两点的最近公共祖先,对于这个问题,直接向上找 ...
随机推荐
- js 引号 转义字符 json字符串
element_obj.NewTitle.value = json_obj.NewTitle.replace(/\"/g, "\""); model.NewTi ...
- CSS3 阴影与圆角边框
㈠css3的新特性实际应用 ⑴文本阴影效果,用代码编写的方式实现 ⑵鼠标悬停的动态效果 左侧三幅图片,上面初始状态是没有说明文本的,但把鼠标放在上面的时候,这个图片上面就出现了说明文字 ⑶分栏 ...
- Flash大文件断点续传解决方案
核心原理: 该项目核心就是文件分块上传.前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题. * 如何分片: * 如何合成一个文件: * 中断了从哪个分片开 ...
- UOJ #460. 新年的拯救计划 神仙题+构造
对于这个神仙题,我还能说什么~ 第一个答案=$n/2$ 还是比较好猜的. 对于构造这个树,大概就是先从 $1$ 号节点向 $n/2$ 距离以内都连一条边,再在第 $n/2$ 个节点进行这个操作,然后从 ...
- C++自动糖果贩卖机
#include<map> #include<vector> #include<cstdio> #include<iostream> #include& ...
- 事件总线(EventBus)
Vue.prototype.$EventBus = new Vue() 不建议用,尽量用vuex,eventbus过于消耗浏览器资源 傻瓜版状态管理 一般的状态传递是在同时显示的情况下,倘若是在不同时 ...
- 第七周课程总结&实验报告五
实验四 类的继承 实验目的 理解抽象类与接口的使用: 了解包的作用,掌握包的设计方法. 实验要求 掌握使用抽象类的方法. 掌握使用系统接口的技术和创建自定义接口的方法. 了解 Java 系统包的结构. ...
- python3笔记八:python数据类型-Number数字
一:学习内容 数字类型分类:整数.浮点数.复数.布尔值 数字类型转换 数字类型的数学功能:abs().max().min().pow().round().math函数.random函数 二:数字类型分 ...
- leetcode-easy-dynamic-121 Best Time to Buy and Sell Stock
mycode 70.94% 思路:其实没必要去考虑在计算了一个max-min后,后面又出现了一个新的的最小值的情况,因为res取值就是取自己和新的res的最大值 在遇见max值之前,遇见新的最小值, ...
- RF问题收集
console中不打印日志 报错信息: 修改pop方法: try: result = result.decode('UTF-8') except UnicodeDecodeError: pass re ...