[Graph theory] LCA (recent public ancestor) Tarjan offline algorithm

Source: Internet
Author: User

Good reference: http://taop.marchtea.com/04.04.html The following map and some of the text reproduced in this article

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.

Because it is an offline algorithm, I want to save the input information, order problem.

If the two nodes U, v are distributed in the left and right subtree of a node T, then this node T is the nearest common ancestor of U and v. Further, given that a node itself is the case of LCA, it is learned that:


If a node t is one of the ancestors of two nodes U, V, and the two nodes are not distributed in a subtrees tree of the node T, but in the Zuozi and right subtree of the node T, then the node T is the nearest common ancestor of the two nodes U and v.

This theorem is the basis of the Tarjan algorithm.

2.4. Application example of Tarjan algorithm

Cite An example from this article. ( the Blue font is the description I added )

i) access to the Zuozi 1

STEP 1: Starting at root node 1, start accessing nodes 1, 2, 3 (thesame node in the same collection as ancestors)

STEP 2:2 left subtree node 3 access complete ( when Zuozi access is complete, here is the child, to set its ancestor node as the parent node, that is, ancestor[3]=2, 3,2 become a collection )

STEP 3: Start accessing Nodes 4, 5, 6 in the right subtree of 2

Node 5 in the left subtree of STEP 4:4 has been accessed.

STEP 5: Start Access to node 6 of the right subtree of 4

STEP 6: The left and right sub-tree of Node 4 are all visited, so 4, 5, 6 of any two nodes of the LCA are 4(when a vertex subtree all access and return the vertex, you can query the vertex related to the recent public ancestor information, such as query 4,5 's common ancestor, here used and search set , with 4 as the root node, at the beginning of the father[4]=4 (defined as 1 can also, as long as there is a unique identity on the line), 4,5 first merge, father[4]=5, then 4,6 merge, father[find (4)] = 6, that is, father[5]=6, when 4, The nearest public ancestor of 5 is ancestor[find (5)] =ancestor[6]= 4. )

STEP 7:2 of the Zuozi, the right subtree has been visited, so 2, 3, 4, 5, 6 any two nodes of the LCA are 2 (2,3,4,5,6 in the same set)

As mentioned above: to this step7, when access to the end point 2 of Zuozi (3), and the right subtree (4, 5, 6), Node 2, 3, 4, 5, 6 of these 5 nodes, any two nodes of the nearest public ancestor are 2.

II) access to the right sub-tree of 1

STEP 8:1 Zuozi Access completed, start Access to 1 right subtree

STEP 9: Start accessing Nodes 7, 8 in the right subtree of 1

STEP 10

STEP 11

Nodes 7 and 8 in the right subtree of STEP 12:1 have been accessed.

When this step12 is reached, the most recent public ancestor of 5 nodes (2, 3, 4, 6, 7), and the right subtree (8, 2) of the nodes 3, 4, 5, 6, 7, 8, 7 are all two, after accessing the 1 Zuozi.

The Zuozi and right subtree of STEP 13:1 are all accessed (all nodes are in the same collection at the end)

From the above example, we can see that using this Tarjan algorithm can solve our LCA problem.

Process Summary:

The above process is clear that when a subtree of a vertex is fully accessed and returned to the vertex, a query involving that vertex can be queried, and the vertex and subtree have a common nearest ancestor, which is the vertex, and it may be doubtful that the nearest public ancestor of the vertex below the vertex is not necessarily the vertex, such as the 2 vertex below 5 , 6, their nearest public ancestor was 4. This is the magic of recursion, it is from the top to the bottom, and then back from the bottom up, constantly upward update, the collection is also constantly merging, the initial problem is 4,5,6 such a leaf node of the subtree, when returned 4 o'clock, look at the input and 4 related queries There is no, if the query 4,6 that must be 4, At this time there is no related query for Vertex 2, because the recursive return does not return to 2, so each return to a node (node is the vertex), see if there is no query about the node in the input. When all the left subtree of the root node is accessed, all the nodes of Zuozi and the ancestors of the root node become the root node, then all nodes of Zuozi and the closest common ancestor of the root node and any node of the right subtree are the root nodes. Take a closer look, this algorithm is really amazing.

Implementation method:

The topic is to create an adjacency table for each vertex, that is, to save all vertices that are directly connected to the vertex through an edge, the graph is bidirectional, plus two sides when adding edges.

The above is an adjacency table for each vertex based on the given graph, an adjacency table for each vertex based on the input, and a record of the query as a query, and the results of 3,5 and 5,3 are the same.

And check the use of the very ingenious, need path compression, the collection based on the search returned from a small expanding, including all the vertices inside the ancestors are also in real-time updates, the last of all the ancestors of the vertex root.

Here is the bin God Template:

POJ 1330

First enter T as the number of test data sets, then enter an n, indicating that there are n vertices, the next n-1 line, indicating that there are n-1 edges, each row consists of two vertices u, V, the next line is to query the two vertex u,v, that is, the nearest public ancestor of U,v. This group of test data only involves a query.

MAXN vertex maximum number, MAXQ maximum number of queries. Ans[i] Saves the results of the query I entered, starting from 0.

#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h>using namespace std;const int maxn=10010;//vertex number const int maxq=100;//The maximum number of queries, depending on the topic, there is actually only one query per group of data.//and check set int f[maxn];//root node int find (int x    {if (f[x]==-1) return x; Return F[x]=find (F[x]);}    void Unite (int u,int v) {int x=find (u);    int Y=find (v); if (x!=y) f[x]=y;} And check the end of the bool vis[maxn];//node to access int ancestor[maxn];//node I ancestor struct edge{int to,next;}    Edge[maxn*2];int head[maxn],tot;void addedge (int u,int v)//adjacency header insertion method plus side {edge[tot].to=v;    Edge[tot].next=head[u]; head[u]=tot++;}    struct query{int q,next; int index;//query number, which is the order of input}query[maxq*2];int ans[maxn*2];//store the results of each query, the following table 0~q-1, in fact, should be open maxq size.    int H[maxn],tt;int q;//The number of queries required in the topic void addquery (int u,int v,int index)//adjacency header interpolation method plus ask {query[tt].q=v;    Query[tt].next=h[u];    Query[tt].index=index;    h[u]=tt++;    query[tt].q=u;//equivalent to two queries, such as query 3,5 and 5,3 results are the same, 3 is the head node of the adjacency table has 5, 5 is the head node of the adjacency table has 3 query[tt].next=h[v]; QUERY[TT]. Index=index; h[v]=tt++;}    void Init () {tot=0;    memset (head,-1,sizeof (head));    tt=0;    memset (h,-1,sizeof (h));    memset (vis,0,sizeof (VIS));    memset (F,-1,sizeof (f)); memset (ancestor,0,sizeof (ancestor));}    void LCA (int u) {ancestor[u]=u;    Vis[u]=true;        for (int i=head[u];i!=-1;i=edge[i].next)//and vertex U-related vertex {int v=edge[i].to;        if (Vis[v]) continue;        LCA (v);        Unite (U,V); Ancestor[find (U)]=u;//the left and right children of U to the ancestor of U} for (int i=h[u];i!=-1;i=query[i].next)//Look at the input query there is no U node-related {int v=qu        ERY[I].Q;    if (Vis[v]) Ans[query[i].index]=ancestor[find (v)];    }}bool flag[maxn];//is used to determine the root node of the int t;int N,u,v;int main () {int a,b,c;    scanf ("%d (%d):%d", &a,&b,&c);    cout<<a<<b<<c;    scanf ("%d", &t);        while (t--) {scanf ("%d", &n);        Init ();        memset (flag,0,sizeof (flag));            for (int i=1;i<n;i++) {scanf ("%d%d", &u,&v); Flag[v]=true;//in Addedge (U,V);        Addedge (V,u);            } The q=1;//topic has only one set of queries for (int i=0;i<q;i++) {scanf ("%d%d", &u,&v);        AddQuery (U,v,i);        } int root;                for (int i=1;i<=n;i++) {if (!flag[i]) {root=i;            Break        }} LCA (root);    for (int i=0;i<q;i++) printf ("%d\n", Ans[i]); } return 0;}


[Graph theory] LCA (recent public ancestor) Tarjan offline algorithm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.