您的位置:首页 > 其它

LCA tarjan 离线算法学习

2012-05-08 13:48 274 查看

最近公共祖先(Least Common Ancestors) LCA

定义:对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。另一种理解方式是把T理解为一个无向无环图,而LCA(T,u,v)即u到v的最短路上深度最小的点。

离线算法Tarjan:

  利用并查集优越的时空复杂度,我们可以实现LCA问题的O(n+Q)算法,这里Q表示询问的次数。Tarjan算法基于深度优先搜索的框架,对于新搜索到 的一个结点,首先创建由这个结点构成的集合,再对当前结点的每一个子树进行搜索,每搜索完一棵子树,则可确定子树内的LCA询问都已解决。其他的LCA询 问的结果必然在这个子树之外,这时把子树所形成的集合与当前结点的集合合并,并将当前结点设为这个集合的祖先。之后继续搜索下一棵子树,直到当前结点的所 有子树搜索完。这时把当前结点也设为已被检查过的,同时可以处理有关当前结点的LCA询问,如果有一个从当前结点到结点v的询问,且v已被检查过,则由于 进行的是深度优先搜索,当前结点与v的最近公共祖先一定还没有被检查,而这个最近公共祖先的包涵v的子树一定已经搜索过了,那么这个最近公共祖先一定是v 所在集合的祖先。

看一下算法描述吧:

View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 10005
typedef struct edge{
int v;
edge *next;
edge(){next=NULL;}
}edge;
edge map[maxn],e[maxn<<1];
edge query[maxn];
int cnt,n;
int s,t;
int fa[maxn],anc[maxn];
bool vis[maxn];
int ans[maxn][maxn];
int in[maxn];
void addedge(int u,int v){
edge *p=e+cnt++;
p->v=v; p->next=map[u].next; map[u].next=p;
}
void init(){
cnt=0;
int a,b;
memset(map,0,sizeof(map));
memset(query,0,sizeof(query));
memset(anc,0,sizeof(anc));
memset(in,0,sizeof(in));
scanf("%d",&n);
for(int i=0;i<n-1;i++){
scanf("%d%d",&a,&b);
addedge(a,b);
in[b]++;
}
scanf("%d%d",&s,&t);
edge *p=e+cnt++,*q=e+cnt++;
p->v=t; p->next=query[s].next; query[s].next=p;
q->v=s; q->next=query[t].next; query[t].next=q;
for(int i=0;i<=n;i++)fa[i]=i;
}
int find(int u){
if(fa[u]!=u) fa[u]=find(fa[u]);
return fa[u];
}
void munion(int u,int v){
int a=find(u),b=find(v);
if(a<b) fa[b]=a;
else if(b<a) fa[a]=b;
}
void dfs(int u){
anc[u]=u;
for(edge *e=map[u].next;e;e=e->next)if(!vis[e->v]){
dfs(e->v);
munion(u,e->v);
anc[find(u)]=u;
}
vis[u]=1;
for(edge *e=query[u].next;e;e=e->next){
int v=e->v;
if(vis[v]) {
ans[u][v]=ans[v][u]=anc[find(v)];
}
}
}
int solve(){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(!in[i]) dfs(i);
return ans[s][t];
}
int main()
{
freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--){
init();
printf("%d\n",solve());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: