/******************************************************************** ** @file nuaa1025.cpp ** @date Fri Apr 29 22:33:37 2011 ** @brief 此种算法比较适合,在一棵树上有多个询问的情况 ** ********************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAX 100002 int fa[MAX]; int depth[MAX]; /*获取node节点的深度*/ int getDepth(int node){ if(fa[node]==0)return 1;/*如果是根结点*/ /*如果此节点没求出,捎带着也把他的父节点的深度也求出来*/ else if(depth[node]==-1)return depth[node]=getDepth(fa[node])+1; /*如果已经求出,直接返回*/ else return depth[node]; } int LCA(int a,int b){ getDepth(a);getDepth(b); /*将两点调整到同一深度上*/ while(depth[a]<depth[b])b=fa[b]; while(depth[b]<depth[a])a=fa[a]; while(a!=b){ a=fa[a];//同时向祖先推进,直到相遇 b=fa[b]; }return a; } int main(int argc, char *argv[]) { memset(depth,-1,sizeof(depth)); int n,m;int num; scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&fa[i]); } scanf("%d",&m); int u,v; for(int i=0;i<m;++i){ scanf("%d%d",&u,&v); printf("%d/n",LCA(u,v)); } return 0; }
/******************************************************************** ** @file poj1330.cpp ** @date Fri Apr 29 15:34:08 2011 ** @brief ** 最近公共祖先LCA:Tarjan算法 LCA问题的Tarjan离线算法[摘抄] 利用并查集优越的时空复杂度,我们可以实现LCA问题的O(n+Q)算法,这里Q表示询问 的次数。 Tarjan算法基于深度优先搜索的框架,对于新搜索到的一个结点,首先创建由这个结点 构成的集合,再对当前结点的每一个子树进行搜索,每搜索完一棵子树,则可确定子树 内的LCA询问都已解决。其他的LCA询问的结果必然在这个子树之外,这时把子树所形 成的集合与当前结点的集合合并,并将当前结点设为这个集合的祖先。之后继续搜索下 一棵子树,直到当前结点的所有子树搜索完。这时把当前结点也设为已被检查过的,同 时可以处理有关当前结点的LCA询问,如果有一个从当前结点到结点v的询问,且v已被 检查过,则由于进行的是深度优先搜索,当前结点与v的最近公共祖先一定还没有被检 查,而这个最近公共祖先的包涵v的子树一定已经搜索过了,那么这个最近公共祖先一定 是v所在集合的祖先。 ********************************************************************/ #include<iostream> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define MAX 10001 int indegree[MAX];/*查找根结点时用到*/ vector<int>tree[MAX];/*存储树结构*/ vector<int>Que[MAX]; int ancestor[MAX]; int f[MAX]; bool vis[MAX]; void init(int n){/*初始化*/ memset(indegree,0,sizeof(indegree)); memset(vis,false,sizeof(vis)); for(int i=0;i<n;++i){ f[i]=i;ancestor[i]=0; tree[i].clear(); Que[i].clear(); } } void input(int n){ int a,b; for(int i=1;i<n;++i){ scanf("%d%d",&a,&b); tree[a].push_back(b); indegree[b]++; } scanf("%d%d",&a,&b); Que[a].push_back(b); Que[b].push_back(a); } int find(int u){ if(u==f[u])return u; else return f[u]=find(f[u]); } bool unin(int x,int y){/*合并成功返回true 否则返回false*/ int a=find(x);int b=find(y); if(a==b)return false; else f[a]=b; return true; } void LCA(int u){ ancestor[u]=u; for(int i=0;i<tree[u].size();++i){ LCA(tree[u][i]); unin(u,tree[u][i]); ancestor[find(u)]=u; } vis[u]=true; for(int i=0;i<Que[u].size();++i){ if(vis[Que[u][i]]){ cout<<ancestor[find(Que[u][i])]<<endl; return; } } } int main(int argc, char *argv[]) { int n,t; cin>>t; for(int i=0;i<t;++i) { cin>>n; init(n); input(n); int u; for(int i=1;i<n;++i) if(indegree[i]==0){ u=i;break; } LCA(u); } return 0; }