For the recent public ancestor problem, let's first look at this nature. When the recent public ancestor of the two nodes (u, v) is X, then we can be sure to say, when performing post-order traversal, you must first access all the child trees of X before returning to the node where X is located. This is the core idea of using the Tarjan algorithm to solve recent common ancestor problems.
At the same time, how can we ensure that this is the recent public ancestor? In this way, because we gradually backtrack data, each time we access a subtree of node X, we put all the nodes in the subtree into the set where node X is located, and we set the ancestor of all elements in this set to the node X. Then, when we access all the sub-trees of a node, we mark the node as the point where the ancestor has been found.
At this time, Tarjan adopts the offline method to solve the problem of the recent public ancestor, so this is the case. Assume that the node We just accessed is A, so let's see if B has been accessed at another point we asked together. If B has already been accessed, at this time, the recent public ancestor must be the C ancestor of the collection where B is located, because our access to a is transferred from the recent public ancestor C, in addition, when we switched from the subtree B of C to A, we have set the ancestor of B to C. At the same time, C is also the ancestor of, C must be the recent common ancestor of A and B.
For all nodes in a subtree, the ancestor is the root node of the subtree. Therefore, we often need to update the ancestor of the entire subtree during backtracking. To facilitate processing, we use and query sets to maintain the ancestor of a set. The total time complexity is O (n + q), because DFS is O (n), and then the query is probably O (q.
This is the offline Tarjan algorithm. It may be hard to say clearly, but it is easy to write. The following is the code of the question I have posted on poj 1470. It is a simple solution to the LCA problem.
/*author UESTC_Nowitzki */#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <vector>using namespace std;const int MAX=1000;int indegree[MAX];int ancestor[MAX];int set[MAX];int vis[MAX];int time[MAX];vector<int> adj[MAX];vector<int> que[MAX];void init(int n){ memset(time,0,sizeof(time)); memset(vis,0,sizeof(vis)); memset(indegree,0,sizeof(indegree)); for(int i=1;i<=n;i++) { adj[i].clear(); que[i].clear(); set[i]=i; ancestor[i]=i; }}int find(int k){ int r=k; while(set[r]!=r) r=set[r]; int i=k,j; while(set[i]!=r) { j=set[i]; set[i]=r; i=j; } return r;}void dfs(int i){ int len=adj[i].size(); for(int j=0;j<len;j++) { int son=adj[i][j]; dfs(son); set[son]=i; ancestor[find(i)]=i; } vis[i]=1; len=que[i].size(); for(int j=0;j<len;j++) { int son=que[i][j]; if(vis[son]) { int ans=ancestor[find(son)]; time[ans]++; } }}int main(){ int n,i,t,a,b; while(scanf("%d",&n)!=EOF) { init(n); for(i=0;i<n;i++) { scanf("%d:(%d)",&a,&t); while(t--) { scanf("%d",&b); indegree[b]++; adj[a].push_back(b); } } scanf("%d",&t); while(t--) { while(getchar()!='('); scanf("%d%d",&a,&b); que[a].push_back(b); que[b].push_back(a); } while(getchar()!=')'); for(i=1;i<=n;i++) { if(indegree[i]==0) { // printf("root=%d\n",i); dfs(i); break; } } for(i=1;i<=n;i++) { if(time[i]>0) printf("%d:%d\n",i,time[i]); } } return 0;}