LCA问题的常见解法有两种:Tarjan算法和RMQ算法。两种算法有一个共同点,就是都是基于深度优先搜索的框架。本文以POJ1470为例,对这两种算法做一个总结。 Tarjan: #include <iostream> using namespace std; const int MAXN=910; struct TreeNode{int data,next;}nodes[MAXN]; int head[MAXN],qu[MAXN][MAXN],match[MAXN],par[MAXN],height[MAXN],ancester[MAXN],n,ni; bool visited[MAXN]; void read() { int son_num,son_data,root; for(int i=0;i<n;i++) { scanf(" %d : ( %d )",&root,&son_num); while(son_num--) { scanf("%d",&son_data); nodes[ni].data=son_data; nodes[ni].next=head[root]; head[root]=ni++; } } } int findRoot() { bool visited[MAXN]; int i; memset(visited,false,sizeof(visited)); for(i=0;i<ni;i++)visited[nodes[i].data]=true; for(i=1;;i++) if(!visited[i])return i; } int findAncester(int i) { while(par[i]!=i)i=par[i]; return i; } void unionset(int i,int j) { i=findAncester(i); j=findAncester(j); if(height[j]<height[i])par[j]=i; else if(height[i]<height[j])par[i]=j; else if(i!=j) { par[i]=j; height[j]++; } } void dfs(int root) { par[root]=root; int si=head[root]; while(si!=0) { dfs(nodes[si].data); unionset(root,nodes[si].data); ancester[findAncester(root)]=root; si=nodes[si].next; } visited[root]=true; for(int i=1;i<=qu[root][0];i++) if(visited[qu[root][i]])match[ancester[findAncester(qu[root][i])]]++; } void query() { int q,a1,a2; scanf("%d",&q); while(q--) { scanf(" ( %d %d )",&a1,&a2); qu[a1][++qu[a1][0]]=a2; qu[a2][++qu[a2][0]]=a1; } } void output() { for(int i=1;i<=n;i++) if(match[i])printf("%d:%d/n",i,match[i]); } void init() { memset(head,0,sizeof(head)); memset(match,0,sizeof(match)); memset(height,0,sizeof(height)); memset(visited,false,sizeof(visited)); for(int i=1;i<MAXN;i++)qu[i][0]=0; ni=1; } int main() { while(cin>>n) { init(); read(); query(); dfs(findRoot()); output(); } return 0; } RMQ: #include <iostream> using namespace std; const int MAXN=910; struct TreeNode{int data,next;}nodes[MAXN]; int head[MAXN],st[MAXN*3][12],enter[MAXN*3],pos[MAXN],level[MAXN],match[MAXN],ei,ni,n; void read() { int son_num,son_data,root; for(int i=0;i<n;i++) { scanf(" %d : ( %d )",&root,&son_num); while(son_num--) { scanf("%d",&son_data); nodes[ni].data=son_data; nodes[ni].next=head[root]; head[root]=ni++; } } } int findRoot() { bool visited[MAXN]; int i; memset(visited,false,sizeof(visited)); for(i=0;i<ni;i++)visited[nodes[i].data]=true; for(i=1;;i++) if(!visited[i])return i; } void dfs(int root,int l) { int si=head[root]; level[root]=l; enter[ei]=root; pos[root]=ei++; while(si!=0) { dfs(nodes[si].data,l+1); si=nodes[si].next; enter[ei++]=root; } } void initST() { int i,j; for(i=0;i<ei;i++)st[i][0]=enter[i]; for(j=1;(1<<j)<=ei;j++) for(i=0;i+(1<<j)<=ei;i++) { int m1=st[i][j-1],m2=st[i+(1<<(j-1))][j-1]; if(level[m1]<level[m2])st[i][j]=m1; else st[i][j]=m2; } } int rmq(int from,int to) { int span=to-from+1,bin=0; while((1<<(bin+1))<=span)bin++; int m1=st[from][bin],m2=st[to-(1<<bin)+1][bin]; return level[m1]<level[m2]?m1:m2; } void query() { int q,a1,a2; scanf("%d",&q); while(q--) { scanf(" ( %d %d )",&a1,&a2); a1=pos[a1]; a2=pos[a2]; if(a1>a2)swap(a1,a2); match[rmq(a1,a2)]++; } } void output() { for(int i=1;i<=n;i++) if(match[i])printf("%d:%d/n",i,match[i]); } void init() { memset(head,0,sizeof(head)); memset(match,0,sizeof(match)); ei=0; ni=1; } int main() { while(cin>>n) { init(); read(); dfs(findRoot(),0); initST(); query(); output(); } return 0; }