倍增版LCA

lac即最近公共祖先,u和v最近公共祖先就是两节点公用的祖先中深度最大的

比如



其中

lca(1,2)=4,

lca(2,3)=4,

lca(3,5)=1,

lca(2,5)=4;

如何求LCA?

树上倍增版:

  1. 预处理每一个节点的深度depth[i];
  2. 选定两节点;
  3. 将深度大的节点往上跳,跳到与另一节点相同深度;
  4. 然后两个节点一起往上跳,直到两个节点重合;
  5. 那么这个节点就是两个节点的lca;

那么怎么让计算机实现“跳”?

我们可以用倍增思想

f[i][j]表示第i个节点往上跳2^j个节点所到达的祖先

那么

f[i][j]=f[f[i][j-1]][j-1]

意思是

从i往上跳2j个节点所到达的节点可以转化为从i往上跳2(j-1)再往上跳2^(j-1)个,而f[i][j-1]在之前通过递推已经推出来了

初始化Code:

void init()
{
for(int j=1;j<=N;j++)
{
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
}

题目

给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入样例#1:
    5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
输出样例#1:
    4
4
1
4
4
说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int head[500010],depth[500010];
int n,m,s,cnt,f[500010][20];
int N=0;
bool vis[500010];
struct Edge
{
int next;
int to;
}e[500010];
inline int Read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
return x*f;
}
void add(int from,int to)
{
cnt++;
e[cnt].to=to;
e[cnt].next=head[from];
head[from]=cnt;
}
void dfs(int x)
{
vis[x]=true;
for(int i=head[x];i;i=e[i].next)
{
int now=e[i].to;
if(!vis[now])
{
depth[now]=depth[x]+1;
f[now][0]=x;
dfs(now);
}
}
}
void init()
{
for(int j=1;j<=N;j++)
{
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
}
int lca(int x,int y)
{
if(depth[x]>depth[y]) swap(x,y);
int d=depth[y]-depth[x];
for(int i=0;i<=N;i++)
{
if((1<<i) & d)
y=f[y][i];
}
if(x==y) return x;
for(int i=N;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
n=Read();m=Read();s=Read();
N=log(n)/log(2)+1;
for(int i=1;i<n;i++)
{
int x,y;
x=Read();y=Read();
add(x,y);
add(y,x);
}
dfs(s);
init();
while(m--)
{
int x,y;
x=Read();y=Read();
printf("%d\n",lca(x,y));
}
return 0;
}

据我所知LCA的算法不只一种,比如:

ST表算法

Tarjan算法

树链剖分算法

倍增法只是其中一种在线算法,但已经够用

其他算法请小伙伴们自行查阅吧!

大图预警!!!

镇楼

LCA最近公共祖先(倍增版)的更多相关文章

  1. lca 最近公共祖先

    http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...

  2. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)

    Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...

  3. LCA(最近公共祖先)模板

    Tarjan版本 /* gyt Live up to every day */ #pragma comment(linker,"/STACK:1024000000,1024000000&qu ...

  4. CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )

    CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...

  5. LCA近期公共祖先

    LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...

  6. LCA 近期公共祖先 小结

    LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...

  7. lca最近公共祖先(模板)

    洛谷上的lca模板题--传送门 学了求lca的tarjan算法(离线),在洛谷上做模板题,结果后三个点超时. 又把询问改成链式前向星,才ok. 这个博客,tarjan分析的很详细. 附代码-- #in ...

  8. LCA最近公共祖先-- HDU 2586

    题目链接 Problem Description There are n houses in the village and some bidirectional roads connecting t ...

  9. LCA (最近公共祖先)倍增做法 —— O(nlogn)预处理 O(logn)(在线)查询

    pa[a][j] 表示 a 结点的 2^j倍祖先(j = 0时 为直接父亲,j = 1时为父亲的父亲……) 1.首先预处理出所有结点的深度值dep和父亲结点 void dfs(int u, int f ...

随机推荐

  1. Linux IPC实践(3) --具名FIFO

    FIFO具名/命名管道 (匿名)管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信. 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道;命 ...

  2. 对Java配置文件中敏感信息进行加解密的工具类

    在 JavaEE 配置文件中,例如 XML 或者 properties 文件,由于某些敏感信息不希望普通人员看见,则可以采用加密的方式存储,程序读取后进行解密. 常见的如: 数据库用户密码,短信平台用 ...

  3. 【UML 建模】UML建模语言入门 -- 静态图详解 类图 对象图 包图 静态图建模实战

    发现个好东西思维导图, 最近开始用MindManager整理博客 . 作者 :万境绝尘  转载请注明出处 : http://blog.csdn.net/shulianghan/article/deta ...

  4. g++和gcc的相同点和区别

    gcc和g++的区别和联系 gcc和g++都是GNU(一个组织)的编译器. 1.对于.c后缀的文件,gcc把它当做是C程序:g++当做是C++程序: 2.对于.cpp后缀的文件,gcc和g++都会当做 ...

  5. SpriteBuilder弹出菜单层造成卡顿的解决办法

    如果你注意到略微的卡顿(延时)(lag due to low framerate)当显示一个全屏的弹出菜单时,你可以简单的设置_levelNode(_levelNode是主游戏界面中的背景层,所有游戏 ...

  6. AngularJS进阶(六)AngularJS+BootStrap实现弹出对话框

    AngularJS+BootStrap实现弹出对话框 参考资料: http://angular-ui.github.io/bootstrap/#/modal https://www.zybuluo.c ...

  7. Android高级控件(一)——ListView绑定CheckBox实现全选,增加和删除等功能

    Android高级控件(一)--ListView绑定CheckBox实现全选,增加和删除等功能 这个控件还是挺复杂的,也是项目中应该算是比较常用的了,所以写了一个小Demo来讲讲,主要是自定义adap ...

  8. 速度之王 — LZ4压缩算法(二)

    LZ4 (Extremely Fast Compression algorithm) 项目:http://code.google.com/p/lz4/ 作者:Yann Collet 本文作者:zhan ...

  9. SharePoint 列表项通过自定义WebService读取

    简述:给其他系统提供集成,发现SharePoint自带的WebService各种不好使,索性就自己写一点,也当做自己学习的记录了.当然内容比较简单,希望大侠们不要介意,也不要骂我啊.好了,进入正题吧. ...

  10. mac os 中如何修改顶栏图标的顺序

    很简单哦! 按住 cmd键同时鼠标选中那个图标,直接拖到你想要的位置即可.