poj 1330 LCA最近公共祖先
今天学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最近公共祖先的更多相关文章
- POJ 1330 LCA最近公共祖先 离线tarjan算法
题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集 ...
- 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 ...
- lca 最近公共祖先
http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...
- LCA 近期公共祖先 小结
LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...
- 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 最近公共祖先 tarjan离线 总结 结合3个例题
在网上找了一些对tarjan算法解释较好的文章 并加入了自己的理解 LCA(Least Common Ancestor),顾名思义,是指在一棵树中,距离两个点最近的两者的公共节点.也就是说,在两个点通 ...
随机推荐
- 终结 finalize()和垃圾回收(garbage collection)
1.为什么要有finalize()方法? 假定你的对象(并非使用new)获得了一块"特殊"的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以他不知道该如何释放该对象 ...
- 1.初入GitHub
进入github官网,点击右上角注册按钮. 填写账号名,邮箱和密码 选择免费的公开仓库,点击完成就提示注册成功了. ps:付费一般是给企业用户使用的,用来存放一些不公开的代码.所以是付费的 ...
- Linux下栈溢出导致的core dump
1 问题产生 前两天在干活的时候,写好的一个daemon程序,一跑就core,连main函数都进不去.从来没见过这阵势的职场新人被吓尿了,幸好不是在生产环境上测试.找来同事帮忙,看了好久也没看出问题, ...
- java集合框架的讲解
下面要开始java中相关集合框架的学习啦. Are you ready?Let's go~~ 今天要讲解的Java中的集合框架. 1) 首先查看jdk中Collection类的源码后会发现如下内容: ...
- Unity 使用TexturePackerGUI打包图集 Sprite 图片边上有线
原来遇到的问题 保存下解决方法 修改Shape Padding图片间距的值为4
- mysql 查询性能优化第一章 为什么查询速度会慢
一 为什么查询速度会慢 在尝试编写快速的查询之前,咱们需要清除一点,真正重要的是响应时间.如果把查询看成是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要有 优化查询,实际上要 ...
- linux忘记密码/修改密码
方法一:用set password命令 首先,登陆mysql ? 1 mysql -u root -p 然后执行set password命令 ? 1 set password for root@loc ...
- Linux用户深度管理
linux系统是多任务.多用户的系统. 用户.用户组的概念 每个文件和进程,都需要对应一个用户和用户组. linux系统是通过UID和GID来是识别用户和组的. 其中用户名等同于人名(人类识别), ...
- .NET Core资源汇总
前言 首先庆祝.NET Core 2.0今天发布. 最近一两年.NET的关注度直线下降, 大部分开发人员转去了其他平台, 国内的机会也越来越少了. 行情虽然如此, 仍在坚守.NET平台的开发人员还是要 ...
- HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 题意: 给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加 ...