poj1330 lca 最近公共祖先问题学习笔记
首先推荐两个博客网址:
http://dongxicheng.org/structure/lca-rmq/
http://scturtle.is-programmer.com/posts/30055.html
[转]tarjan算法的步骤是(当dfs到节点u时):
1 在并查集中建立仅有u的集合,设置该集合的祖先为u
1 对u的每个孩子v:
1.1 tarjan之
1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先
举例说明(非证明):
假设遍历完10的孩子,要处理关于10的请求了
取根节点到当前正在遍历的节点的路径为关键路径,即1-3-8-10
集合的祖先便是关键路径上距离集合最近的点
比如此时:
1,2,5,6为一个集合,祖先为1,集合中点和10的LCA为1
3,7为一个集合,祖先为3,集合中点和10的LCA为3
8,9,11为一个集合,祖先为8,集合中点和10的LCA为8
10,12为一个集合,祖先为10,集合中点和10的LCA为10
你看,集合的祖先便是LCA吧,所以第3步是正确的
道理很简单,LCA(u,v)便是根至u的路径上到节点v最近的点
为什么要用祖先而且每次合并集合后都要确保集合的祖先正确呢?
因为集合是用并查集实现的,为了提高速度,当然要平衡加路径压缩了,所以合并后谁是根就不确定了,所以要始终保持集合的根的祖先是正确的
关于查询和遍历孩子的顺序:
wikipedia上就是上文中的顺序,很多人的代码也是这个顺序
但是网上的很多讲解却是查询在前,遍历孩子在后,对比上文,会不会漏掉u和u的子孙之间的查询呢?
不会的
如果在刚dfs到u的时候就设置u为visited的话,本该回溯到u时解决的那些查询,在遍历孩子时就会解决掉了
这个顺序问题就是导致我头大看了很久这个算法的原因,也是絮絮叨叨写了本文的原因,希望没有理解错= =
对于这道题
题意:求最近公共祖先lca
下面是学来的tarjan代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime> using namespace std; class Edge
{
public:
int to;
int next;
}e[]; int n,T,cnt;
int f[],depth[],anc[],p[];
bool visited[],In[]; inline void Add_edge(const int & x,const int & y)
{
e[++cnt].to=y;
e[cnt].next=p[x];
p[x]=cnt;
return ;
} inline int get_anc(const int &x)
{
return f[x]==x ? x:f[x]=get_anc(f[x]);
} inline void Union(const int & x,const int & y)
{
int S,T;
S=get_anc(x);
T=get_anc(y);
if(S==T)return ;
if(depth[S]<=depth[T])
f[S]=T,depth[S]+=depth[T];
else
f[T]=S,depth[T]+=depth[S];
return ;
} void Dfs(const int &S,const int d)
{
int i;
depth[S]=d;
for(i=p[S];i;i=e[i].next)
{
Dfs(e[i].to,d+);
} return ;
} int Lca_tarjan(const int & s,const int & t,const int & u)
{
int i,temp; anc[u]=u;
for(i=p[u];i;i=e[i].next)
{
temp=Lca_tarjan(s,t,e[i].to);
if(temp)return temp;
Union(u,e[i].to);
anc[get_anc(u)]=u;
} visited[u]=true;
if(s==u&&visited[t])
return anc[get_anc(t)];
if(t==u&&visited[s])
return anc[get_anc(s)]; return ;
} inline void Init()
{
cnt=;
memset(depth,,sizeof(depth));
memset(visited,,sizeof(visited));
memset(anc,,sizeof(anc));
memset(p,,sizeof(p));
memset(e,,sizeof(e));
memset(In,,sizeof(In)); for(int i=;i<=n;++i)
{
f[i]=i;
} return ;
} int main()
{
//freopen("1330.in","r",stdin); int i,x,y,s,t,S; scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
Init();
for(i=;i<n;++i)
{
scanf("%d%d",&x,&y);
Add_edge(x,y);
In[y]=true;
} for(S=;S<=n;++S)
if(!In[S])break; scanf("%d%d",&s,&t);
Dfs(S,);
printf("%d\n",Lca_tarjan(s,t,S));
} return ;
}
poj1330 lca 最近公共祖先问题学习笔记的更多相关文章
- LCA最近公共祖先---倍增法笔记
先暂时把模板写出来,A几道题再来补充 此模板也是洛谷上的一道模板题 P3379 [模板]最近公共祖先(LCA) #pragma GCC optimize(2) //o2优化 #include < ...
- lca 最近公共祖先
http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)
Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...
- LCA(最近公共祖先)模板
Tarjan版本 /* gyt Live up to every day */ #pragma comment(linker,"/STACK:1024000000,1024000000&qu ...
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
CodeVs.1036 商务旅行 ( LCA 最近公共祖先 ) 题意分析 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从 ...
- LCA近期公共祖先
LCA近期公共祖先 该分析转之:http://kmplayer.iteye.com/blog/604518 1,并查集+dfs 对整个树进行深度优先遍历.并在遍历的过程中不断地把一些眼下可能查询到的而 ...
- LCA 近期公共祖先 小结
LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...
- LCA 最近公共祖先 (笔记、模板)
求lca的方法大体有三种: 1.dfs+RMQ(线段树 ST表什么的) 在线 2.倍增 在线 3.tarjan 离线 ps:离线:所有查询全输入后一次解决 在线:有一个查询输出一次 以下模板题为 洛谷 ...
- LCA最近公共祖先(POJ1330)
题目链接:http://poj.org/problem?id=1330 解题报告: 先将一个子节点,深搜每一个根节点,并标记. 然后深索另一个子节点,当发现访问过了,就找到了最近的公共祖先. #inc ...
随机推荐
- bzoj3662
数学 其实我们发现不用每个数都去试一下,只要确定每个数字有几个就可以确定这个数.所以我们先搜索一下,然后检验. 但是这样太慢了,所以我们打表. 打出1-30的结果,然后取模. 打表的程序好像弄丢了.. ...
- Request returned failure status 401
Request returned failure status 401.Invalid OpenStack Identity credentials.
- Coursera Algorithms week4 基础标签表 练习测验:Inorder traversal with constant extra space
题目原文: Design an algorithm to perform an inorder traversal of a binary search tree using only a const ...
- Linux系统下vim常用快捷键及功能
1. 什么是vim Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器,在vi的基础上改进和增加了很多特性. vim编辑器是Linux系统下标准的编辑器,作用相当于windows系统中的记 ...
- E20171028-hm
stick n. 棍棒,棍枝; 枝条; 操纵杆; 球棍; stopwatch n. (赛跑等记时用的) 秒表,跑表; agency n. 代理; 机构; 力量; various adj. ...
- Sublime Text Version 3.0,Build3143注册码
1.打开sublime text软件2.Help->Enter License3.复制以下BEGIN LICENSE和END LICENSE之间的部分,粘贴进去.(注意:不要复制BEGIN LI ...
- python自动化测试学习笔记-2-字典、元组、字符串方法
一.字典 Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串.数字.元组等其他容器模型. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割, ...
- python爬虫值requests模块
- 基于如下5点展开requests模块的学习 什么是requests模块 requests模块是python中原生的基于网络请求的模块,其主要作用是用来模拟浏览器发起请求.功能强大,用法简洁高效.在 ...
- Mac OS安装octave出现的问题-'error:terminal type set to 'unknown'的解决'
学习Machine learning需要使用Octave语言,毕竟Andrew Ng (恩达.吴)力荐.本机系统Mac OS X EI Capitan, 其实什么系统都无所谓了,安装原理都是一样的. ...
- Java系列学习(六)-数组
1.方法: (1)定义: 完成特定功能块的代码,在有些语言中也叫函数 (2)格式: (3)方法的重载 [在同一个类中,方法名相同,参数列表不同,与返回值无关] 2.数组 (1)定义 存储同一种数据类型 ...