LCA recent public ancestor
Tarjan He's a base idea of a base (off-line) algorithm and its algorithm implementation
This article is the network data collation or partial reprint or part original, the reference article is as follows:
Https://www.cnblogs.com/JVxie/p/4854719.html
http://blog.csdn.net/ywcpig/article/details/52336496
https://baike.baidu.com/item/Recent public ancestor/8918834?fr=aladdin
recent public ancestor abbreviation for LCA(Lowest Common Ancestor):
The so-called LCA: When given a root tree T, for any two nodes U, V, find a node farthest from the root x, so that x is both U and V ancestors, X is the nearest public ancestor of U, v.
In a more general explanation: in a tree without a ring, each node must have its father node and ancestor node, and the recent public ancestor, is two nodes in this tree depth the largest public ancestor node. In other words, it is the nearest common ancestor node of two points on this tree. So LCA is mainly used to deal with the path when two points have only one determined shortest path. LCA can also treat itself as an ancestor node.
In order to simplify, this paper uses two-fork tree to discuss.
For example, for an ordinary two-fork tree as shown:
The nearest common ancestor of Node 3 and Node 4 is node 2, i.e. LCA (3,4) =2 .
It is important to note that when two nodes are on the same subtrees tree.
For example, the nearest common ancestor of Node 3 and Node 2 is 2, i.e. LCA (3,2) =2.
Similarly:LCA (5,6) =4,LCA (6,10) =1.
Clear test instructions, we will try to solve the problem. The intuitive approach may be to discuss whether or not to find a tree for two forks, which is the first thought the general people think of. In addition, there are tarjan algorithms, multiplication algorithms, and conversion to RMQ problems (to find the extremum of a certain interval).
Let's first talk about the brute force solution:
Solution One: If it is a two-fork search tree, such as:
So start with the roots:
- If the current node T is greater than the node U, V, the U, v are on the left side of T, so their common ancestor must be in the left subtree of T, so from the record of T continue to find;
- If the current node T is less than the node U, V, the U, v are on the right side of T, so their common ancestor must be in the right sub-tree of T, so from the right subtree of T to continue to find;
- If the current node T satisfies U <t < V, it means that U and V are separated on both sides of T, so the current node T is the nearest public ancestor;
- And if u is the ancestor of V, then U is the nearest public ancestor, and if V is the ancestor of U, then V is the nearest public ancestor.
The pseudo-code looks like this:
int query (node T, node U, node v) { int left = U.value; int right = V.value; //two fork in the search tree, if the left node is larger than the right node, swap. Don't know why to Exchange if (left > right) { int temp = left; left = right; right = temp; } while (True) { //if T is less than u, V, go to the right subtree of T if (T.value < left) { t = T.right; //if T is greater than u, V, look in the left subtree of t } else if (T.value > right) { t = T.left; } else { return T.value; } } }
If it is not a binary lookup tree, for each query, the violence traverses all points, the time complexity is O (n*q), and Q is the number of queries. Obviously, N and Q are generally not very small. Here a little ...
Solution Two: Tarjan (offline) algorithm Solving LCA
The offline algorithm refers to the unified input and then the unified output, not the edge input side real-time output. The complexity of the Tarjan algorithm is O (n+q) and Q is the number of queries. Equivalent to one-time batch processing, the first to know all the query, only to be asked.
The following is a detailed introduction to the basic idea of the Tarjan algorithm: It doesn't matter what you see, we'll simulate it later.
1. Choose a point as the root node, starting at the root node.
2. Traverse the point u all child nodes V, and mark those child nodes V has been visited.
3. If v has a child node, return 2, or the next step.
4. Merge V to U.
5. Look for the point V with the current point you have a query relationship.
6. If V has been visited, then you can confirm that the nearest common ancestor of U and V is the Father Node A that V was merged into.
The traversal will need to use Dfs to traverse, as for the merger, the most optimal way is to use and check the set to merge two nodes.
the following pseudo-code:
Tarjan (U)//marge and find for and look up the merge function and lookup function {for each (U,V)//Access all U child nodes v {tarjan (v); Continue to traverse Marge (u,v); Merge V to u, Mark V is visited; } for each (U,E)//Access all and u have inquire about the relationship of E {if e was accessed; the nearest public ancestor of U,e is find (e); }}
View Code
Let's start by simulating the LCA with Tarjan and then summarize it.
Let's say we have a set of data 9 nodes with 8 edge connectivity as follows:
1--2,1--3,2--4,2--5,3--6,5--7,5--8,7--9 is the tree shown
We are going to find the points of the nearest common ancestor for 9 and 8,4 and 6,7 and 5,5 and 3;
Set f[] array as the parent node array of the set, initialize the f[i]=i,vis[] array as the array to be accessed, initially 0;
The following begins the simulation process :
Take 1 for root node, search down to find there are two sons 2 and 3;
Search first 2, found that 2 have two sons 4 and 5, first search 4, found that 4 has no child nodes, then look for their relationship with the point;
Found 6 and 4 have a relationship, but Vis[6]=false, that is, 6 has not been searched, so do not operate;
Found no and 4 have asked the point of the relationship, return to the previous search, update Vis[4]=true, indicating that 4 has been searched, and then update f[4]=2, indicating that 4 is merged into 2, such as:
continued to search 5, found that 5 had two sons 7 and 8;
Search first 7, found that 7 has a child node 9, search 9, found no child nodes, looking for their relationship with the point;
found that 8 and 9 have a relationship, but Vis[8]=false, that is, 8 has not been searched, so do not operate;
Found no and 9 have questioned the point of the relationship, return to the previous search, update vis[9]=true;
Indicates that 9 has been searched, updated f[9]=7;
Back to 7, found that 7 have not been searched for the sub-node, looking for its relationship with the point;
found that 5 and 7 have a relationship, but vis[5]=false, so do not operate;
Found that there is no relationship with 7 points, return to the previous search, update vis[7]=true;
Indicates that 7 has been searched and updated f[7]=5. such as:
Continue to search 8, found that 8 have no child nodes, then look for their relationship with the point;
Discovery 9 has a relationship with 8, at this time vis[9]=true, then their recent public ancestor for find (9) = 5; (Think about it here)
the Order of Find (9) is f[9]=7-->f[7]=5-->f[5]=5 return 5;
Found no relationship with 8 points, return to the previous search, update vis[8]=true;
Indicates that 8 has been searched and updated f[8]=5. Such as:
Back to 5 found 5 there is no search for the sub-node, looking for its relationship with the point;
found that 7 and 5 had a relationship at this time vis[7]=true, so their recent public ancestor for find (7) = 5;
the Order of Find (7) is f[7]=5-->f[5]=5 return 5;
Also found that 5 and 3 have a relationship, but vis[3]=false, so do not operate, at this time 5 of the child nodes are all searched;
Return to the previous search, update Vis[5]=true, indicating that 5 has been searched, updated f[5]=2;
Back to 2 found 2 no unfinished sub-nodes, looking for their relationship with the point;
Found no relationship with 2 points, return to the previous search, update vis[2]=true;
Indicates that 2 has been searched and updated f[2]=1. such as:
Then search 3, found that 3 has a child node 6;
Searching for 6, found that 6 had no child nodes, then looked for 6 related points, found 4 and 6 have a relationship;
At this time vis[4]=true, so their nearest public ancestor is find (4) = 1;
the Order of Find (4) is f[4]=2-->f[2]=1-->f[1]=1 return 1;
Found that there is no relationship with 6 points, return to the previous search, update Vis[6]=true, indicating that 6 has been searched;
Update f[6]=3. such as:
Back to 3 found 3 no not searched sub-nodes, then look for the point with 3 relations;
found that 5 and 3 have a relationship, at this time vis[5]=true, then their nearest public ancestor is find (5) = 1;
the Order of Find (5) is f[5]=2-->f[2]=1-->f[1]=1 return 1;
Found no relationship with 3 points, return to the previous search, update vis[3]=true; Update f[3]=1.
such as :
finally found 1 No searched child nodes also have no relationship point, at this time can exit the entire DFS.
After this DFS we came up with all the answers.
Summarize:
Tarjan offline algorithm, will be asked to store first, then combine and check set and DFS,
if both points are vis[]==1, then output their father
P3379 "template" recent public ancestor (LCA)
https://www.luogu.org/problemnew/show/3379
2370 trees in a small room
http://codevs.cn/problem/2370/
1036 Business Travel
http://codevs.cn/problem/1036/
LCA Tarjan Algorithm Template Reference code C + +
https://www.luogu.org/problemnew/solution/P3379 last one
Https://www.cnblogs.com/fish7/p/4006056.html
http://blog.csdn.net/qq_24451605/article/details/43114243
http://blog.csdn.net/mzyupengju/article/details/47146789
http://blog.csdn.net/tekim/article/details/77750093
Https://www.cnblogs.com/jsawz/p/6723221.html
Note: LCA recent public ancestor Tarjan (offline) algorithm