poj 1330 Nearest Common Ancestors(LCA 基于二分搜索+st&rmq的LCA)
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 30147 | Accepted: 15413 |
Description
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
Output
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
#include<iostream>
#include<vector>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=;
const int logN=;
vector<int> G[N];
int root;
int parent[][N];
int fa[N],n,x,y,s,t;
int depth[N]; void dfs(int v,int p,int d)
{
parent[][v]=p;
depth[v]=d;
for(int i=;i<G[v].size();i++)
if (G[v][i]!=p)
{
fa[G[v][i]]=v;
dfs(G[v][i],v,d+);
}
}
void init(int V)
{
int root;
for(int i=;i<=n;i++)
if (fa[i]==) {root=i; break;}
dfs(root,-,);
for(int k=;k+<logN;k++)
{
for(int v=;v<=V;v++)
{
if(parent[k][v]<) parent[k+][v]=-;
else parent[k+][v]=parent[k][parent[k][v]];
}
}
}
int lca(int u,int v)
{
if (depth[u]>depth[v]) swap(u,v);
for(int k=;k<logN;k++)
{
if ((depth[v]-depth[u])>>k & )
v=parent[k][v];
}
if (u==v) return u;
for(int k=logN-;k>=;k--)
{
if (parent[k][u]!=parent[k][v])
{
u=parent[k][u];
v=parent[k][v];
}
}
return parent[][u];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++) {G[i].clear(); fa[i]=;}
for(int i=;i<=n-;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
fa[y]=x;
}
init(n);
scanf("%d%d",&s,&t);
int croot=lca(s,t);
printf("%d\n",croot);
}
return ;
}
ST&RMQ 的LCA
#include<iostream>
#include<vector>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
const int M=;
int tot,cnt,n,T,s,t;
int head[N]; //记录i节点在e数组中的其实位置
int ver[*N]; //ver:保存遍历的节点序列,长度为2n-1,从下标1开始保存
int R[*N]; // R:和遍历序列对应的节点深度数组,长度为2n-1,从下标1开始保存
int first[N]; //first:每个节点在遍历序列中第一次出现的位置
bool vis[N]; //遍历时的标记数组
int dp[*N][M],fa[N]; struct edge
{
int u,v,next;
}e[*N];
void dfs(int u ,int dep)
{
vis[u] = true;
ver[++tot] = u;
first[u] = tot;
R[tot] = dep;
for(int k=head[u]; k!=-; k=e[k].next)
if( !vis[e[k].v] ) //这里可以省个vis数组,如果在dfs改成dfs(当前节点,当前节点的父亲,当前节点的深度) 具体可以参照connections with cities {
int v=e[k].v;
dfs(v,dep+);
ver[++tot]=u;
R[tot]=dep;
}
}
void ST(int n)
{
for(int i=;i<=n;i++)
dp[i][] = i;
for(int j=;(<<j)<=n;j++)
{
for(int i=;i+(<<j)-<=n;i++)
{
int a = dp[i][j-] , b = dp[i+(<<(j-))][j-];
dp[i][j] = R[a]<R[b]?a:b;
}
}
} int RMQ(int l,int r)
{
int k=(int)(log((double)(r-l+))/log(2.0));
int a = dp[l][k], b = dp[r-(<<k)+][k]; //保存的是编号
return R[a]<R[b]?a:b;
} int LCA(int u ,int v)
{
int x = first[u] , y = first[v];
if(x > y) swap(x,y);
int res = RMQ(x,y);
return ver[res];
} void addedge(int u,int v)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
memset(fa,,sizeof(fa));
cnt=; tot=;
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
fa[y]=x;
}
for(int i=;i<=n;i++)
if (fa[i]==) { dfs(i,); break;}
ST(*n-);
scanf("%d%d",&s,&t);
printf("%d\n",LCA(s,t));
}
return ;
}
poj 1330 Nearest Common Ancestors(LCA 基于二分搜索+st&rmq的LCA)的更多相关文章
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- POJ - 1330 Nearest Common Ancestors(基础LCA)
POJ - 1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000KB 64bit IO Format: %l ...
- POJ.1330 Nearest Common Ancestors (LCA 倍增)
POJ.1330 Nearest Common Ancestors (LCA 倍增) 题意分析 给出一棵树,树上有n个点(n-1)条边,n-1个父子的边的关系a-b.接下来给出xy,求出xy的lca节 ...
- POJ 1330 Nearest Common Ancestors(lca)
POJ 1330 Nearest Common Ancestors A rooted tree is a well-known data structure in computer science a ...
- POJ 1330 Nearest Common Ancestors 倍增算法的LCA
POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节 ...
- LCA POJ 1330 Nearest Common Ancestors
POJ 1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 24209 ...
- POJ 1330 Nearest Common Ancestors 【LCA模板题】
任意门:http://poj.org/problem?id=1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000 ...
- POJ 1330 Nearest Common Ancestors (LCA,dfs+ST在线算法)
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14902 Accept ...
- POJ 1330 Nearest Common Ancestors(Targin求LCA)
传送门 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 26612 Ac ...
随机推荐
- UVa 1603 破坏正方形
https://vjudge.net/problem/UVA-1603 题意:有一个火柴棍组成的正方形网格,计算至少要拿走多少根火柴才能破坏所有正方形. 思路:从边长为1的正方形开始遍历,将正方形的边 ...
- MVC ---- 如何使用Action委托
先建立一个Serven 类 public class Seven { public static void TestSeven1() { List<User> userList = Fiv ...
- Quartz.NET简介及入门指南
Quartz.NET简介 Quartz.NET是一个功能完备的开源调度系统,从最小的应用到大规模的企业系统皆可适用. Quartz.NET是一个纯净的用C#语言编写的.NET类库,是对非常流行的JAV ...
- Linux进程内存布局(翻译)
Anatomy of a Program in Memory 在一个多任务OS中,每个进程都运行在它自己的内存沙箱中.这个沙箱就是虚拟地址空间,在32位下就是一块容量为4GB的内存地址.内核将这些虚拟 ...
- Linux基础※※※※连接XShell到Ubuntu 14.04 LTS
参考链接: 博客链接1:http://blog.csdn.net/lichangzai/article/details/39379153 百度百科:http://baike.baidu.com/lin ...
- c++ 匹配A容器中最先出现的b容器中的元素,返回iterator,(find_first_of)
#include <iostream> // std::cout #include <algorithm> // std::find_first_of #include < ...
- Linq 常用方法解释
/// <summary> /// linq /// </summary> public class Linq { /// <summary> /// 测试 /// ...
- dataframe使用笔记
dates=pd.date_range(',periods=6) #创建固定频度的时间序列 df=pd.DataFrame(np.random.randn(6,4),index=dates,colum ...
- 使用 rlist 包处理嵌套数据结构
在前面的章节中,我们已经学习了存储表的关系型数据库,支持嵌套数据结构的非关系型数据库.在 R 中,最常见的嵌套数据结构就是列表对象.之前的章节都关注操作表格数据.本节,我们一起玩转作者开发的 rlis ...
- 启动tomcat一闪而过问题调试并解决
之前一直用myelise+tomcat启动项目很正常,今天在尝试用绿色版tomcat8时,点击startup.bat文件时,一闪而过,tomcat未正常启动,也无法看到错误信息.搜索网络查找到调试方法 ...