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; }
相关文章推荐
- LCA三种算法学习(离线算法tarjan+在线算法转rmq+在线倍增)例题poj1330、1470;hdu4547、2874
- HDU OJ 2586 How far away ?【LCA的Tarjan离线算法】
- POJ1470Closest Common Ancestors 最近公共祖先LCA 的 离线算法 Tarjan
- POJ 1986 Distance Queries(LCA Tarjan离线算法)
- 【模板】tarjanLCA [2017年6月计划 学习tarjanLCA]
- HDU4547(CD操作)LCA+Tarjan离线算法
- LCA的离线算法(Tarjan)与在线算法(RMQ)详解
- (算法)Tarjan离线算法解决LCA问题 (附POJ 1470 Closest Common Ancestors 代码)
- LCA离线算法学习笔记
- HDU 2586 How far away ? LCA的Tarjan离线算法
- POJ1986 DistanceQueries 最近公共祖先LCA 离线算法Tarjan
- 树上两点的最近公共祖先-Tarjan_LCA离线算法
- 最小公共祖先(LCA)离线算法_Tarjan c++实现
- hdu 4547 Tarjan LCA 离线算法
- [笔记]LCA 最近公共祖先---tarjan离线算法
- vijos_1460_拉力赛_LCA tarjan离线算法
- LCA最近公共祖先的离线算法(Tarjan)和在线算法(ST)
- hdu 2874 lca-tarjan离线算法(模板)
- 【算法笔记】LCA问题-tarjan 离线算法
- LCA的Tarjan离线算法