今天学LCA,先照一个模板学习代码,给一个离线算法,主要方法是并查集加上递归思想。

再搞,第一个离线算法是比较常用了,基本离线都用这种方法了,复杂度O(n+q)。通过递归思想和并查集来寻找最近公共祖先,自己模拟下过程就可以理解了。

然后就是在线算法,在线算法方法就很多了,比较常用的是LCA的RMQ转换,然后还有线段树,DP等,最后效率最高的就是倍增法了每次查询O(LogN)

这道题是离线的。

给出离线的Tarjan和倍增算法吧。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 10001
int f[MAXN];
int r[MAXN];
int indegree[MAXN];
int vis[MAXN];
vector<int>hash[MAXN],Qes[MAXN];
int ancestor[MAXN];
void init(int n)
{
int i;
for(int i=1;i<=n;i++)
{
r[i]=1;
f[i]=1;
indegree[i]=0;
vis[i]=0;
ancestor[i]=0;
hash[i].clear();
Qes[i].clear();
}
}
int find(int n)
{
if(f[n]!=n)
f[n]=find(f[n]);
return f[n];
} int Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a==b)
return 0;
else if(r[a]<r[b])
{
f[a]=b;
r[b]+=r[a];
}
else
{
f[b]=a;
r[a]+=r[b];
}
return 1;
}
void LCA(int u)
{
ancestor[u]=u;
int size=hash[u].size();
for(int i=0;i<size;i++)
{
LCA(hash[u][i]);
Union(u,hash[u][i]);
ancestor[find(u)]=u;
}
vis[u]=1;
size=Qes[u].size();
for(int i=0;i<size;i++)
{
if(vis[Qes[u][i]]==1)
{
printf("%d\n",ancestor[find(Qes[u][i])]);
return ;
}
}
} int main()
{
int T,s,t,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init(n);
for(int i=1;i<=n-1;i++)
{ scanf("%d%d",&s,&t);
hash[s].push_back(t);
indegree[t]++;
}
scanf("%d%d",&s,&t);
Qes[s].push_back(t);
Qes[t].push_back(s);
for(int j=1;j<=n;j++)
{
if(indegree[j]==0)
{
LCA(j);
break;
}
}
}
return 0;
}

倍增法:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int N=10002;
const int Log=20;
int dp[N][Log],depth[N],deg[N];
struct Edge
{
int to;
Edge *next;
}edge[2*N],*cur,*head[N];
void addedge(int u,int v)
{
cur->to=v;
cur->next=head[u];
head[u]=cur++;
}
void dfs(int u)
{
depth[u]=depth[dp[u][0]]+1;
for(int i=1;i<Log;i++) dp[u][i]=dp[dp[u][i-1]][i-1];
for(Edge *it=head[u];it;it=it->next)
{
dfs(it->to);
}
}
int lca(int u,int v)
{
if(depth[u]<depth[v])swap(u,v);
for(int st=1<<(Log-1),i=Log-1;i>=0;i--,st>>=1)
{
if(st<=depth[u]-depth[v])
{
u=dp[u][i];
}
}
if(u==v) return u;
for(int i=Log-1;i>=0;i--)
{
if(dp[v][i]!=dp[u][i])
{
v=dp[v][i];
u=dp[u][i];
}
}
return dp[u][0];
}
void init(int n)
{
for(int i=0;i<=n;i++)
{
dp[i][0]=0;
head[i]=NULL;
deg[i]=0;
}
cur=edge;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,u,v;
scanf("%d",&n);
init(n);
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
deg[v]++;
dp[v][0]=u;
}
for(int i=1;i<=n;i++)
{
if(deg[i]==0)
{
dfs(i);
break;
}
}
scanf("%d%d",&u,&v);
printf("%d\n",lca(u,v));
}
return 0;
}

poj 1330 LCA最近公共祖先的更多相关文章

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

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

  2. poj 1330 【最近公共祖先问题+fa[]数组+ 节点层次搜索标记】

    题目地址:http://poj.org/problem?id=1330 Sample Input 2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 1 ...

  3. lca 最近公共祖先

    http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...

  4. LCA 近期公共祖先 小结

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

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

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

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

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

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

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

  8. LCA近期公共祖先

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

  9. LCA 最近公共祖先 tarjan离线 总结 结合3个例题

    在网上找了一些对tarjan算法解释较好的文章 并加入了自己的理解 LCA(Least Common Ancestor),顾名思义,是指在一棵树中,距离两个点最近的两者的公共节点.也就是说,在两个点通 ...

随机推荐

  1. SQL Server数据库基础笔记

    启动和停止SQL Server服务三种形式 后台启动服务 计算机->右键->管理->服务和应用程序->服务->sql server(MSSQLSERVER) SQL Se ...

  2. 多系统重装其中Win7后的启动引导列表恢复

    重装Win7后会导致原grub引导被覆盖,要修复grub需要一张Ubuntu的LiveCD(安装光盘),用LiveCD启动电脑,进入Try Ubuntu(试用Ubuntu),进入之后打开终端,做如下几 ...

  3. Hbase架构与原理

    Hbase架构与原理 HBase是一个分布式的.面向列的开源数据库,该技术来源于 Fay Chang所撰写的Google论文"Bigtable:一个结构化数据的分布式存储系统".就 ...

  4. animate.css的使用

    前面的话 animate.css是一个使用CSS3的animation制作的动画效果的CSS集合,里面预设了很多种常用的动画,且使用非常简单.本文将详细介绍animate.css的使用 引入 anim ...

  5. 【NO.12-1】Jmeter - 在Linux执行性能测试的方法 [1]

    前面讲过在Windows执行性能测试的方法,就是这篇了<jmeter - 一个完整的接口测试的脚本>, 在Windows执行性能测试之前,首先要有1个性能测试脚本嘛, 但是这个性能测试脚本 ...

  6. python——变量

    参考资料: Python程序设计与实现 变量名的命名规则 仅仅由大.小写英文字母,下划线(_),数字(不可作为变量名的开头)组合而成: 不能使用Python关键字和函数名作为变量名: 变量名不能包含空 ...

  7. Ecplise插件安装方法

    eclipse3.5以前: 安装Eclipse插件无非两种方式: 1.直接copy插件到features/plugins目录 2.在links目录下创建链接文件 eclipse3.5及以后版本: 1. ...

  8. 【windows】常用快捷键

    浏览器 ctrl shift del 清除网页缓存 文件系统 win+e 打开文件窗口 win+r 运行命令窗口 win+l 锁定桌面 win+m 最小化窗口 ctrl+shift +n 创建文件夹

  9. 一句话搞定-phpStudy安装yaf扩展

    首先下载phpStudyX64位的,然后傻瓜式安装,安装完下载yaf,由于yaf扩展的网站在国外很难下载,需要FQ,所以我这里下载了yaf5.6nts.zip,解压后把php_yaf.dll这个文件粘 ...

  10. Android笔记: ListView基本用法-ArrayAdapter

    ListView实现过程: 新建适配器->添加数据源到适配器->视图加载适配器 数据适配器: 把复杂的数据(数组.链表.数据库.集合等)填充在制定的试图界面上. 两种常用数据适配器 Arr ...