先瞎扯几句

树上倍增的经典应用是求两个节点的LCA

当然它的作用不仅限于求LCA,还可以维护节点的很多信息

求LCA的方法除了倍增之外,还有树链剖分、离线tarjan ,这两种日后再讲(众人:其实是你不会吧:unamused:。。。)

思想

树上倍增嘛,顾名思义就是倍增

相信倍增大家都不默认,著名的rmq问题的$O(n*logn)$的解法就是利用倍增实现的

在树上倍增中,我们用

$f[j][i]$表示第$j$号节点,跳了$2^j$步所能到达的节点

$deep[i]$表示$i$号节点的深度

然后用这两个数组瞎搞搞就能整出LCA来啦

众人::wrench:  :hammer: :hocho:

实现

deep&&f[i][0]

首先,$f[i][0]$(也就是一个节点的上面的节点)容易求得,只要对整棵树进行一边dfs就好,在dfs的时候我们顺便可以求出$deep$数组

for(int i=head[now];i!=-1;i=edge[i].nxt)if(!deep[edge[i].v])deep[edge[i].v]=deep[now]+1,f[edge[i].v][0]=now,dfs(edge[i].v);

这段代码应该不难理解

f[j][i]

那么我们怎么维护$f$数组呢?

不难得到$f[j][i]=f[f[j][i-1]][i-1]$ 众人:难!

其实真的不难,一张图就可以解释明白啦

这句话的意思其实是说,一个节点跳$2^j$所能到达的节点实际上是跳$2^{i-1}$所能到达的节点再往上跳$2^{j-1}$步

注意$2^i=2^{i-1}+2^{i-1}$

代码:

for(int i=1;i<=19;i++)    for(int j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1];

 

LCA

接下来要进入最核心的部分啦,

我们如何用$deep$和$f$乱搞搞出$x$和$y$的LCA呢?

按照书上倍增算法的介绍

我们求LCA需要分为两步

设$deep[x]>deep[y]$

  1. 让$x$向上跳,跳到与$y$深度相同位置
  2. 让$x$和$y$同时向上跳,跳到祖先相同位置

根据二进制分解什么乱七八糟的,这么做一定是对的,其实这个挺显然的,yy一下就好了吧。。。

第一步

if(deep[x]<deep[y])    swap(x,y);for(int i=19;i>=0;i--)if(deep[f[x][i]]>=deep[y])x=f[x][i];

首先处理一下$x$和$y$的深度,保证$deep[x]>deep[y]$

然后尽量让$x$向上跳就好啦,注意这里是可以取到等号的

注意这里可能会出现一种特殊情况

这个时候他们的最近公共祖先就是$y$

if(x==y)    return x;

第二步

同时向上跳,直到祖先相同为止

那么此时他们再向上跳一步所能到达的节点就是LCA啦

for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return    f[x][0];

怎么样?

是不是很简单?

完整代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1000010;
inline void read(int &n) {char c = getchar(); bool flag = 0; n = 0;while (c < '0' || c > '9')    c == '-' ? flag = 1, c = getchar() : c = getchar();while (c >= '0' && c <= '9')    n = n * 10 + c - 48, c = getchar(); flag == 1 ? n = -n : n = n;
}
struct node {int v, nxt;
} edge[MAXN];
int head[MAXN];
int num = 1;
inline void add_edge(int x, int y) {edge[num].v = y;edge[num].nxt = head[x];head[x] = num++;
}
int f[MAXN][21];
int deep[MAXN];
int n, m, root;
void dfs(int now) {for (int i = head[now]; i != -1; i = edge[i].nxt)if (!deep[edge[i].v])deep[edge[i].v] = deep[now] + 1, f[edge[i].v][0] = now, dfs(edge[i].v);
}
void PRE() {for (int i = 1; i <= 19; i++)for (int j = 1; j <= n; j++)f[j][i] = f[f[j][i - 1]][i - 1];
}
int LCA(int x, int y) {if (deep[x] < deep[y])    swap(x, y);for (int i = 19; i >= 0; i--)if (deep[f[x][i]] >= deep[y])x = f[x][i];if (x == y)    return x;for (int i = 19; i >= 0; i--)if (f[x][i] != f[y][i])x = f[x][i], y = f[y][i];return    f[x][0];
}
int main() {memset(head, -1, sizeof(head));read(n); read(m); read(root);for (int i = 1; i <= n - 1; i++) {int x, y; read(x); read(y);add_edge(x, y);add_edge(y, x);}deep[root] = 1;dfs(root);PRE();for (int i = 1; i <= m; i++) {int x, y;read(x); read(y);printf("%d\n", LCA(x, y));}return 0;
}

  

例题

都是些入门难度的题目

洛谷P3379 【模板】最近公共祖先(LCA)

http://www.cnblogs.com/zwfymqz/p/6832524.html

POJ 1986 Distance Queries

http://www.cnblogs.com/zwfymqz/p/7791527.html

HDU 3078 Network

http://www.cnblogs.com/zwfymqz/p/7791617.html

HDU 2586 How far away ?

http://www.cnblogs.com/zwfymqz/p/7791517.html

树上倍增求LCA及例题相关推荐

  1. 树上倍增求LCA详解

    LCA(least common ancestors)最近公共祖先 指的就是对于一棵有根树,若结点z既是x的祖先,也是y的祖先(不要告诉我你不知道什么是祖先),那么z就是结点x和y的最近公共祖先. 定 ...

  2. 《信息学奥赛一本通 提高篇》 第四部分 数据结构 第4章 倍增求LCA

    例题1 点的距离 信息学奥赛一本通(C++版)在线评测系统 例题2 暗的连锁(Poj3417) 信息学奥赛一本通(C++版)在线评测系统 LOj10131 暗的连锁_juruo_xlh-CSDN博客 ...

  3. CodeVS3287[NOIP2013] 货车运输【Kruskal+倍增求LCA】

    题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过 ...

  4. POJ 1986:Distance Queries(倍增求LCA)

    http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点 ...

  5. 【代码源 Div1 - 105】#451. Dis(倍增求LCA)

    problem solution 给出 n 个点的一棵树,每个点有各自的点权,m 次询问两个点简单路径所构成点集的异或和. 直接在树上求LCA,把每个点权放进去预处理一下即可. #include< ...

  6. [KMP][倍增求LCA]JZOJ 4669 弄提纲

    Description 新日暮里中,比冲是一位博学的哲学教授.由于最近要帮学生准备考试,他决定弄个提纲给学生.然而同事van不服气,觉得这样学生就没有了自我思考,便在提纲中添加废话. 比冲很无奈,他想 ...

  7. POJ - 1986 Distance Queries 倍增求LCA

    题意还是很有病的,说了半天后边的方向都没用的,意思就是跟样例一样求两点间的距离,裸的LCA 两个点x,y的距离=dis[x]+dis[y]-2*dis[LCA(x,y)]; 三个点x,y,z的距离=d ...

  8. 蓝书4.1-4.4 树状数组、RMQ问题、线段树、倍增求LCA

    这章的数据结构题很真实 T1 排队 bzoj 1699 题目大意: 求静态一些区间的最大值-最小值 思路: ST表裸题 1 #include<iostream> 2 #include< ...

  9. CF 526F Max Mex(倍增求LCA+线段树路径合并)

    Max Mex 题目地址:https://codeforces.com/contest/1084/problem/F 然后合并时注意分情况讨论: 参考代码: 1 #include<bits/st ...

最新文章

  1. Vue、angular等框架实现双向绑定的原理,核心机制是使用了Object.defineProperty
  2. 近期活动盘点:统计学概论和医疗临床大数据分析讲座、24小时创新挑战:数字时代的人类健康与福祉...
  3. apache日志分析
  4. 条款15: 让operator=返回*this的引用
  5. 对话腾讯安全杨勇:产业互联网带来哪些新的安全挑战
  6. MySQL存储过程相互调用
  7. 【开源项目】基于FFmpeg的PCM和RGB数据统一封装
  8. Java主函数要放在哪个类里_JAVA:主函数一定要放在静态内部类里吗
  9. Mac系统下安装MySQL详细步骤
  10. java 怎么控制暂停5秒钟_java – libGDX暂停运行几秒钟
  11. 可以在一个函数中定义另一个函数_第5周 定义一个函数
  12. 服务器常用的状态码及其对应的含义
  13. proteus实现单片机的仿真
  14. java jdk1.5_jdk1.5 64位官方下载
  15. python实现调用百度图像识别api得到图片识别与检测类别和详细信息以及相关准确度
  16. PowerDesigner导出rtf文件
  17. Acdream 1729 Crime
  18. 计算机深度睡眠状态啥意思,什么是计算机的“深度睡眠”模式?
  19. 健壮F.T.+新裸金属重磅发布!全新升级版ZStack加速新基建!
  20. python 中dtype 为object_DataFrame中的字符串,但dtype是对象

热门文章

  1. 机器码合集开源易语言源码-市场上带多数的
  2. Video视频背景设计企业模板
  3. 如何保证投票公平_从声音玩具淘汰、五条人复活,我看到了《乐队的夏天》的不公平...
  4. emlog独立会员中心模板源码 UserEmlog Ver:1.0
  5. 帝国CMS7.5仿《问答库》题库问答学习平台网站源码 带手机版
  6. 超级抖音腾讯视频V3.6.0小程序源码 前端+后端 支持视频采集和上传
  7. .Net 4.0并行库实用性演练[1]
  8. sqlserver 常用存储过程集锦
  9. Linux Shell脚本入门教程系列之(五)Shell字符串
  10. php 备份数据库 Backup Your MySQL Database Using PHP