【一个蒟蒻的挣扎】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是指在树形结构中两点的最近公共祖先,对于这个问题,直接向上找 ...
随机推荐
- C# 遍历控件名称
List<string> list = new List<string>(); list.Add("textBox2"); list.Add("t ...
- [转] SSH两种登录方式(公私钥)解析
转自:https://www.cnblogs.com/hukey/p/6248468.html SSH登录方式主要分为两种: 1. 用户名密码验证方式 说明: (1) 当客户端发起ssh请求,服务器会 ...
- 好多坑的升级 phpStudy 中 MySQL 版本至 5.7.17
由于本地用的集成环境是 phpStudy 2016,没有找到升级 MySQL 版本的选项,所以自己升级一下. 从官网上下载高版本的 MySQL :https://dev.mysql.com/dow ...
- 暑假集训 #3div2 C Sequence 数字找规律
C. Sequence (64 Mb, 1 sec / test)Integer sequences are very interesting mathematical objects. Let us ...
- HGOI 20190821 慈溪一中互测
Problem A 给出一个$n$个点$m$条边的仙人掌图(每条边最多处于一个简单环中). 使用$c$种颜色对这张图中的顶点染色,使得每一条无向边连接的两个点颜色不同. 求染色的方案数,$mod \ ...
- Springboot入门实战, 使用@Value
今天开始最简单的Springboot应用 entity.Book package com.draymonder.amor.entity; import java.util.List; import o ...
- sh_11_字典的其他操作
sh_11_字典的其他操作 xiaoming_dict = {"name": "小明", "age": 18} # 1. 统计键值对数量 p ...
- 学习sklearn聚类使用
学习利用sklearn的几个聚类方法: 一.几种聚类方法 1.高斯混合聚类(mixture of gaussians) 2.k均值聚类(kmeans) 3.密度聚类,均值漂移(mean shift) ...
- R_Studio(关联)对dvdtrans.csv数据进行关联规则分析
dvdtrans.csv数据:该原始数据仅仅包含了两个字段(ID, Item) 用户ID,商品名称(共30条) #导入arules包 #install.packages("arules&qu ...
- Kotlin的高阶函数和常用高阶函数
Kotlin的高阶函数和常用高阶函数 文章来源:企鹅号 - Android先生 高阶函数的定义 将函数当做参数或者是返回值的函数 什么是高阶函数 可以看看我们常用的 函数: 首先我们可以知道, 是 的 ...