Description
Input
Output
Sample Input
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
Sample Output
4 3
Source
1、比较简单一些的LCA算法,具体做法如下:
具体代码如下
#include <iostream> #include <cstring> #define MAXN 10010 using namespace std; int f[MAXN]; //f[a]=b表示a的父亲是b int lca(int u,int v) //求u和v的树上公共祖先 { if(u==v) return u; //找到了树上公共祖先 int w; while(u) { w=f[u]; f[u]=0; //将f[u]与u之间的连接断开 u=w; } for(;v;v=f[v]) //v向上遍历,找到第一个没有父亲的点,就是答案 if(!f[v]) return v; return 0; } int main() { int T; cin>>T; while(T--) { int n; memset(f,0,sizeof(f)); cin>>n; for(int i=1;i<n;i++) { int u,v; cin>>u>>v; //有向边u->v f[v]=u; //v的父亲是u } int a,b; cin>>a>>b; //最后一行a,b是求lca(a,b) cout<<lca(a,b)<<endl; } return 0; }2、tarjan LCA离线算法
#include <iostream> #include <vector> #include <cstring> #define MAXN 10010 using namespace std; vector<int>son[MAXN]; //保存树 vector<int>ques[MAXN]; //保存查询 typedef vector<int>::iterator it; int inDegree[MAXN]; int f[MAXN]; int ancestor[MAXN]; //ancestor[i]=点i的祖先 bool visit[MAXN]; int ans,n; int depth[MAXN]; void pre_work() { for(int i=1;i<=n;i++) { f[i]=i; inDegree[i]=0; depth[i]=1; visit[i]=false; ancestor[i]=0; son[i].clear(); ques[i].clear(); } } int findSet(int x) { if(f[x]==x) return x; return f[x]=findSet(f[x]); } void Union(int a,int b) { int roota=findSet(a); int rootb=findSet(b); if(roota==rootb) return; else if(depth[roota]<=depth[rootb]) { f[roota]=rootb; depth[rootb]+=depth[roota]; } else { f[rootb]=roota; depth[roota]+=depth[rootb]; } } void lca(int u) //tarjan lca { int Size=son[u].size(); ancestor[u]=u; //标记u的祖先为u for(int i=0;i<Size;i++) //遍历u的儿子 { lca(son[u][i]); Union(u,son[u][i]); ancestor[findSet(u)]=u; } visit[u]=true; Size=ques[u].size(); for(int i=0;i<Size;i++) { if(visit[ques[u][i]]==1) { cout<<ancestor[findSet(ques[u][i])]<<endl; return; } } } int main() { int T; cin>>T; while(T--) { cin>>n; pre_work(); for(int i=1;i<n;i++) { int u,v; cin>>u>>v; inDegree[v]++; son[u].push_back(v); } int a,b; cin>>a>>b; ques[a].push_back(b); ques[b].push_back(a); for(int i=1;i<=n;i++) { if(inDegree[i]==0) //从入度为0的点开始tarjan lca { lca(i); break; } } } return 0; }