LCA问题,利用并查集和dfs寻找最近公共祖先,挺好理解的。
tarjan算法
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> using namespace std; #define N 10005 bool root[N]; int x,y; bool v[N]; int set[N],ans[N],n; int num,to[N],head[N],next[N]; inline void add(int q,int p) { to[num]=p; next[num]=head[q]; head[q]=num++; } int find(int x) { if(x!=set[x]) set[x]=find(set[x]); return set[x]; } void merge(int a,int b) { int p=find(a),q=find(b); if(p==q) return; set[q]=p; } void lca(int k) { ans[k]=k; for(int i=head[k];~i;i=next[i]) { lca(to[i]); merge(k,to[i]); ans[find(to[i])]=k; } v[k]=1; if(k==x) { if(v[y]) printf("%d\n",ans[find(y)]); } else if(k==y) { if(v[x]) printf("%d\n",ans[find(x)]); } } int main() { int cas; cin>>cas; while(cas--) { memset(root,0,sizeof(root)); memset(v,0,sizeof(v)); memset(head,-1,sizeof(head)); num=0; scanf("%d",&n); for(int i=1;i<=n;i++) set[i]=i; for(int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),root[y]=1; scanf("%d%d",&x,&y); for(int i=1;i<=n;i++) { if(!root[i]) { lca(i); break; } } } return 0; }
附上这题的朴素版本,只要一直向上标记就够了。
#include <cstdio> #include <iostream> #include<vector> using namespace std; int fa[10005]; bool v[10005]; int main() { int cas,a,b,n; scanf("%d",&cas); while(cas--) { scanf("%d",&n); memset(fa,0,sizeof(fa)); for(int i=1;i<n;i++) scanf("%d%d",&a,&b),v[i]=0,fa[b]=a; scanf("%d%d",&a,&b); while(a) { v[a]=1; a=fa[a]; } while(!v[b]) { b=fa[b]; } printf("%d\n",b); } return 0; }