给一棵树,和两个点,求这两个点的最近公共祖先(LCA)。刚学完在线算法,再来学个离线的。。但是这个题的查询只有一次,感觉有点浪费了,不管怎么样写法还是一样的:tarjan。
tarjan其实就是一次dfs。利用并查集,在每个节点访问完的时候,把它的祖先置为它的父节点(也就是访问完一棵子树时,树上所有点都在一个集合),然后集中处理与这个节点有关的询问,如果另外一个点已经被访问过了,那么另外那个点所处的集合就是它们的LCA。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string.h>
using namespace std;
#define maxn 10010
struct Edge{
int v;
int pre;
}edge[maxn];
int head[maxn];
vector<int> q[maxn];
int pos;
void addEdge(int u,int v){
edge[pos].pre=head[u];
edge[pos].v=v;
head[u]=pos++;
}
int p[maxn];
int ans;
int find(int u){
if(p[u]==u)return u;
p[u]=find(p[u]);
return p[u];
}
void tarjan(int u){
p[u]=u;
for(int i=head[u];i;i=edge[i].pre){
int v=edge[i].v;
tarjan(v);
p[v]=u;
}
int sz=q[u].size();
for(int i=0;i<sz;i++){
if(p[q[u][i]])ans=find(q[u][i]);
}
}
bool hasp[maxn];
int main(){
int t;
cin>>t;
while(t--){
pos=1;
memset(head,0,sizeof(head));
memset(q,0,sizeof(q));
memset(p,0,sizeof(p));
memset(hasp,0,sizeof(hasp));
int n,u,v;
cin>>n;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addEdge(u,v);
hasp[v]=1;
}
int root;
for(int i=1;i<=n;i++)if(!hasp[i])root=i;
scanf("%d%d",&u,&v);
q[u].push_back(v); q[v].push_back(u);
tarjan(root);
printf("%d\n",ans);
}
return 0;
}
509

被折叠的 条评论
为什么被折叠?



