倍增求LCA:
father【i】【j】表示节点i往上跳2^j次后的节点
可以转移为

father【i】【j】=father【father【i】【j-1】】【j-1】

整体思路:
先比较两个点的深度,如果深度不同,先让深的点往上跳,浅的先不动,等两个点深度一样时,if 相同 直接返回,if 不同 进行下一步;如果不同,两个点一起跳,j从大到小枚举(其实并不大),如果两个点都跳这么多后,得到的点相等,两个点都不动(因为有可能正好是LCA也有可能在LCA上方),知道得到的点不同,就可以跳上来,然后不断跳,两个点都在LCA下面那层,所以再跳1步即可,当father【i】【j】中j=0时即可,就是LCA,返回值结束

(摘自http://blog.csdn.net/dad3zz)

在网络海洋中搜寻很久后找到hzwer的宽搜求deep序,进行了学习。

以下是我的模板代码:

构造访问数组!

void make_bin()
{
bin[0]=1;
for(int i=1;i<=15;i++)
bin[i]=bin[i-1]<<1;
}

简明易懂邻接表!

void Link()
{
for(int i=1;i<=n-1;i++){//n-1 edges;or you can define a m pointing to the number of edges;
scanf("%d%d",&u[i],&v[i]);
u[i+n-1]=v[i];v[i+n-1]=u[i];//双向;
next[i]=first[u[i]];
next[i+n-1]=first[v[i]];//双向;
first[u[i]]=i;
first[v[i]]=i+n-1;//双向;
isroot[v[i]]=true;
}
}

宽搜!

void bfs()
{
int head=0,tail=1;
q[0]=root,vis[root]=true;
while(head^tail){
int now=q[head];head++;
for(int i=1;i<=15;i++){
if(bin[i]<=deep[now])
fa[now][i]=fa[fa[now][i-1]][i-1];
else break;
}
for(int i=first[now];i;i=next[i])
if(!vis[v[i]]){
vis[v[i]]=true;
fa[v[i]][0]=now;
deep[v[i]]=deep[now]+1;
q[tail++]=v[i];
}
}
}

求lca()

int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;i<=15;i++)
if(t&bin[i])x=fa[x][i];
for(int i=15;i>=0;i--)
if(fa[x][i]^fa[y][i])
x=fa[x][i],y=fa[y][i];
if(!(x^y))return y;
return fa[x][0];
}

之后,在poj上找了一个众所周知的例题,poj1330,当做lca入门题

Nearest Common Ancestors
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 24757   Accepted: 12864

Description

A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:


In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor
of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node
x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common
ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.

For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest
common ancestor of y and z is y.

Write a program that finds the nearest common ancestor of two distinct nodes in a tree.

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are
labeled with integers 1, 2,..., N. Each of the next N -1 lines contains a pair of integers that represent an edge --the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test
case contains two distinct integers whose nearest common ancestor is to be computed.

Output

Print exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.

Sample Input

2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5

Sample Output

4
3

Source

Taejon 2002

Source Code

Problem: 1330   User: ksq2013
Memory: 1224K   Time: 32MS
Language: C++   Result: Accepted

ac代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
bool vis[10100],isroot[10100];
int root,q[10100],deep[10100],fa[10100][20];
int n,bin[20],first[10100],next[10100],u[10100],v[10100];
void make_bin()
{
bin[0]=1;
for(int i=1;i<=15;i++)
bin[i]=bin[i-1]<<1;
}
void Link()
{
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u[i],&v[i]);
//u[i+n-1]=v[i];v[i+n-1]=u[i];
next[i]=first[u[i]];
//next[i+n-1]=first[v[i]];
first[u[i]]=i;
//first[v[i]]=i+n-1;
isroot[v[i]]=true;
}
for(int i=1;i<=n;i++)
if(!isroot[i]){
root=i;
break;
}
}
void bfs()
{
int head=0,tail=1;
q[0]=root,vis[root]=true;
while(head^tail){
int now=q[head];head++;
for(int i=1;i<=15;i++){
if(bin[i]<=deep[now])
fa[now][i]=fa[fa[now][i-1]][i-1];
else break;
}
for(int i=first[now];i;i=next[i])
if(!vis[v[i]]){
vis[v[i]]=true;
fa[v[i]][0]=now;
deep[v[i]]=deep[now]+1;
q[tail++]=v[i];
}
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;i<=15;i++)
if(t&bin[i])x=fa[x][i];
for(int i=15;i>=0;i--)
if(fa[x][i]^fa[y][i])
x=fa[x][i],y=fa[y][i];
if(!(x^y))return y;
return fa[x][0];
}
int main()
{
make_bin();
int T;
scanf("%d",&T);
for(;T;T--){
memset(vis,false,sizeof(vis));
memset(isroot,false,sizeof(isroot));
memset(q,0,sizeof(q));
memset(fa,0,sizeof(fa));
memset(deep,0,sizeof(deep));
memset(first,0,sizeof(first));
memset(next,0,sizeof(next));
scanf("%d",&n);
Link();
bfs();
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}

lca入门———树上倍增法(博文内含例题)的更多相关文章

  1. 最近公共祖先算法LCA笔记(树上倍增法)

    Update: 2019.7.15更新 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了. 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了 ...

  2. 树上倍增法求LCA

    我们找的是任意两个结点的最近公共祖先, 那么我们可以考虑这么两种种情况: 1.两结点的深度相同. 2.两结点深度不同. 第一步都要转化为情况1,这种可处理的情况. 先不考虑其他, 我们思考这么一个问题 ...

  3. 【37.48%】【hdu 2587】How far away ?(3篇文章,3种做法,LCA之树上倍增)

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...

  4. LCA离线Tarjan,树上倍增入门题

    离线Tarjian,来个JVxie大佬博客最近公共祖先LCA(Tarjan算法)的思考和算法实现,还有zhouzhendong大佬的LCA算法解析-Tarjan&倍增&RMQ(其实你们 ...

  5. Codeforces 609E (Kruskal求最小生成树+树上倍增求LCA)

    题面 传送门 题目大意: 给定一个无向连通带权图G,对于每条边(u,v,w)" role="presentation" style="position: rel ...

  6. HDU 2586 倍增法求lca

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. 最近公共祖先 LCA 倍增法

    [简介] 解决LCA问题的倍增法是一种基于倍增思想的在线算法. [原理] 原理和同样是使用倍增思想的RMQ-ST 算法类似,比较简单,想清楚后很容易实现. 对于每个节点u , ancestors[u] ...

  8. 最近公共祖先 LCA (Lowest Common Ancestors)-树上倍增

    树上倍增是求解关于LCA问题的两个在线算法中的一个,在线算法即不需要开始全部读入查询,你给他什么查询,他都能返回它们的LCA. 树上倍增用到一个关键的数组F[i][j],这个表示第i个结点的向上2^j ...

  9. 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法

    题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...

随机推荐

  1. SharePoint 2013 场解决方案包含第三方程序集

    前言 当我们使用SharePoint 场解决方案的时候,经常会包含第三方的程序集,而第三方的程序集经常会有强签名的问题,如果有强签名可以部署到GAC,没有的话也可以部署到应用程序下. 那么,很多初学者 ...

  2. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q72-Q74)

    Question 72  You are designing a SharePoint 2010 application and a Web application. You need to desi ...

  3. 免费真机调试 -- Xcode7

    刚新安装了Xcode7 Version 7.1 beta , 据说这个版本可以免费真机调试,于是用了一个新的AppID测试了,发现真的可以免费真机调试了呢!新的appId账号,没有支付每年的99美刀, ...

  4. 利用hexo搭建博客

    利用Hexo搭建博客 以前用Octopress搭过博客,折腾了好久才弄出来,当时看到那巨难看的默认主题,繁琐的操作,一点写东西的欲望都没了. 一次逛微博,看见了Hexo.尝试了一下,真的很好用哦. 下 ...

  5. 关于 python

    关于python的版本: python2.7  和 python3.0 有很大的不同,学习时应因目的而做出选择. 目前用到的python2.7最多, 而web3.0时代 则用到的python3.0 所 ...

  6. WeX5开源免费跨端开发工具-html5 app开发就用WeX5

    http://www.wex5.com/wex5/?utm_source=Baidu-0815

  7. 给现有MVC 项目添加 WebAPI

    1. 增加一个WebApi Controller, VS 会自动添加相关的引用,主要有System.Web.Http,System.Web.Http.WebHost,System.Net.Http 2 ...

  8. Zero to One读后感

    Zero to One是一本不错的书,无论你是在职场还是在创业都应该看看先.书中没有告诉你任何的职业技巧,但是很明确的告诉了你应该有的思考方式,告诉你人与机器的关系,告诉成功企业固有的模式以及你为什么 ...

  9. 用SQL语句建库建表建约束(用SQl语句在指定盘符创建文件夹)

    一 :创建数据库 创建一个数据文件和一个日志文件(MySchool) create database MySchoolon primary      --默认属于primary主文件组,可省略(--数 ...

  10. Tomcat:使用JMX监管Tomcat的几种方式

    Tomcat使用JMX管理方式,在Tomcat的自带应用manager就是使用了JMX方式来管理Tomcat,以此完成Web应用的动态部署.启动.停止. 然而manager应用是一种本地使用JMX接口 ...