概述

对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。

如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4

在本篇中我们先介绍一下倍增算法

我们需要一个数组de[i]来表示每一个节点i的深度,用另一数组parent[i][j]来表示每一节点j向上走2的i次方是哪个节点

我们首先在初始化中算出每个点的深度和它的上一个点是什么(用parent[0][i]表示)

在此后我们进行倍增的处理:parent[1][j]=parent[0][parent[0][j]]......parent[i+1][j]=parent[i][parent[i][j]]

当然如果已经走到根节点了,就将其它的parent全设为0

然后我们就可以搞lca了:给你两个点想x,y,让y成为深的那个,如果x,y深度不等就让y倍增地往上跳。

当x,y深度相等时凡是它俩不相等就倍增地跳,最后它们中任意一个的父节点及他们的最近公共祖先

模板

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int LOG=18;
vector<int>g[500010];
int de[500010];
int parent[LOG+3][500010];
void dfs(int now,int dep,int be)
{     parent[0][now]=be;
      de[now]=dep;
      for(int i=0;i<g[now].size();i++)
         if(g[now][i]!=be)
           dfs(g[now][i],dep+1,now);
}
int lca(int x,int y)
{     if(de[x]>de[y])swap(x,y);
         for(int i=LOG;i>=0;i--)
            if(de[parent[i][y]]>=de[x]&&parent[i][y]>0)
              y=parent[i][y];
      if(x==y)return x;
      for(int i=LOG;i>=0;i--)
         if(parent[i][x]!=parent[i][y])
           x=parent[i][x],y=parent[i][y];
      return parent[0][x];
}
int main()
{     int n,m,s,i,j,k,p,q;
      scanf("%d%d%d",&n,&m,&s);
      for(i=1;i<n;i++){
          int x,y;
          scanf("%d%d",&x,&y);
          g[x].push_back(y);
          g[y].push_back(x);
      }
      dfs(s,0,0);
      for(i=0;i<LOG;i++)
         for(j=1;j<=n;j++)
            if(parent[i][j]<=0)parent[i+1][j]=-1;
              else parent[i+1][j]=parent[i][parent[i][j]];
      for(i=1;i<=m;i++){
          int x,y;
          scanf("%d%d",&x,&y);
          printf("%d\n",lca(x,y));
      }
      return 0;
}

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

  1. LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现

    首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点. 换句话说,就是两个点在这棵 ...

  2. POJ 1330 LCA最近公共祖先 离线tarjan算法

    题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集 ...

  3. caioj 1236 最近公共祖先 树倍增算法模版 倍增

    [题目链接:http://caioj.cn/problem.php?id=1236][40eebe4d] 代码:(时间复杂度:nlogn) #include <iostream> #inc ...

  4. LCA最近公共祖先 Tarjan离线算法

    学习博客:  http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点( ...

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

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

  6. P5836 [USACO19DEC]Milk Visits S 从并查集到LCA(最近公共祖先) Tarjan算法 (初级)

    为什么以它为例,因为这个最水,LCA唯一黄题. 首先做两道并查集的练习(估计已经忘光了).简单来说并查集就是认爸爸找爸爸的算法.先根据线索理认爸爸,然后查询阶段如果发现他们的爸爸相同,那就是联通一家的 ...

  7. LCA 近期公共祖先 小结

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

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

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

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

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

  10. LCA近期公共祖先

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

随机推荐

  1. ASP.NET Core 依赖注入

    一.什么是依赖注入(Denpendency Injection) 这也是个老身常谈的问题,到底依赖注入是什么? 为什么要用它? 初学者特别容易对控制反转IOC(Iversion of Control) ...

  2. 《SpringMVC从入门到放肆》一、概述

    一.SpringMVC概述 View Service Dao DB Spring MVC interface interface Mysql impls impls SpringMVC也叫Spring ...

  3. MIME---multipart类型

    1.3  multipart类型 MIME邮件中各种不同类型的内容是分段存储的,各个段的排列方式.位置信息都通过Content-Type域的multipart类型来定义.multipart类型主要有三 ...

  4. JavaScript正则表达式验证大全(收集)

    以下函数调用方式: ? 1 2 3 4 function check() { var bb = document.getElementById("txt_id").value;// ...

  5. CTF---Web入门第五题 貌似有点难

    貌似有点难分值:20 来源: 西普学院 难度:难 参与人数:7249人 Get Flag:2519人 答题人数:2690人 解题通过率:94% 不多说,去看题目吧. 解题链接: http://ctf5 ...

  6. BZOJ 3670: [Noi2014]动物园【KMP变形 】

    3670: [Noi2014]动物园 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2738  Solved: 1475[Submit][Status ...

  7. hdu_1358Period(kmp找循环前缀)

    题目在这儿 Period Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  8. c++(线性队列)

    这里的线性结构实际上指的就是连续内存的意思,只不过使用“线性”这个词显得比较专业而已.前面一篇博客介绍了现象结构的处理方法,那么在这个基础之上我们是不是添加一些属性形成一种新的数据结构类型呢?答案是肯 ...

  9. [国嵌笔记][005][Linux命令详解]

    用户管理类命令 添加用户:useradd name 删除用户:userdel -r name "-r"表示删除对应用户的目录 修改密码:passwd name 切换用户:su - ...

  10. oracle和mysql分页

    mysql分页 关键字limit,limit m,n 其中m表示起始位置的下标,下标从0开始.n表示要显示的条数,比如要查询一个表的第2到5条数据. ,; oracle分页 关键字rownum, ro ...