First, the concept of carding
Definition: For the two nodes of the root tree T u, V, the nearest common ancestor LCA (T,U,V) represents a node x, which satisfies the ancestor of x which is U, V, and the depth of x as large as possible.
In layman's words, the most recent common ancestor node, the most common ancestor node of two nodes in the tree, is the closest common ancestor node of two points on this tree.
Hint: The Father node is also the ancestor node, and the node itself is its ancestor node.
Give a tree:
The most recent common ancestor of 3 and 5, the nearest public ancestor of 1, 5 and 6, is 2, 2 and 7 of the recent public ancestor 2, 6 and 7, as defined above.
Second, red tape
Attention PAY ATTENTION!!! It is not clear that the binary tree after the post-traversal, and search set, Tarjan algorithm of children's shoes can not look down.
"--tarjan offline algorithm for solving LCA problems"
Summary: Use and check set to complete all queries in a DFS (depth-first traversal). In other words, it is an offline algorithm to have all of the queries read in before the calculation begins.
The nature of the post-order traversal of a binary tree: when the nearest public ancestor of the two nodes (u,v) is x , when a sequential traversal is performed, it is necessary to first access all of the X's subtrees (which contain U, v) before returning to the node where x is located. This nature is the core idea that we use the Tarjan algorithm to solve the problems of recent public ancestors.
Using the graph to speak the algorithm:
As shown, find the critical path P (explained by the key path P content is root-->...-->p2-->p1-->u) of the root node to node U, and the traversed point is located in the path p of a node (for example, p2) Subtree (since the post-traversal nature of the preceding lines illustrates the subsequent access to the subtree node). The first case: when traversing to u v has traversed (U's subtree has been traversed, because U is a sub-tree root node), then v must exist in the subtree PK (also in the subtree of U), at this time LCA (U,V) is equal to the current set of V ancestor PK (hehe, You can figure it out because U is the last root node on the path p, if V is in the subtree of U, then the public ancestor is U recently, and the second case: if V has not been traversed , then the traversal continues, but the LCA (U,V) will not know until it traverses to V, the principle is as above. One thing to note is that, in order to preserve the nature, if a subtree of a node is traversed, the subtree collection of that node needs to be merged.
Third, the algorithm description
first, let's look at some of the algorithms that seek public nearest ancestors and Analyze the performance of these algorithms, where we set the number of queries Q (what is the number of queries?) Read on and you'll understand):
- Violence (actually does not work): For each query, traverse all points, the time complexity is O (n*q).
- Tarjan (offline) algorithm: All queries are resolved once in a single traversal , and the time complexity is O (n+q).
- Multiplication (online) algorithm: To stay in the pit.
"Tarjan Algorithm Process simulation"
First of all:
Condition: We need to find the nearest common ancestor's point pair for <3,5>,<5,6>,<2,7>,<6,7>.
Initialize: ① open a pre array, record the Father node, initialize the Pre[i]=i;② and open a vis array, record whether the node has been accessed, initialize the memset (vis,0,sizeof (VIS)).
Process:
- First Take 1 as the root node, found that it has two child nodes 2 and 3, first search 2 (post-order traversal basic operations), and found that 2 have two sub-nodes 4 and 5, first search and two sub-nodes 6 and 7, first search 6, then found that 6 has No child nodes , and then look for it with ask the node of the relationship (the point pair in the condition for reference) and find that both 5 and 7 have a query relationship with 6, but none have been visited . So return and Mark Vis[6]=1,pre[6]=4;
- Then search 7, found that 7 has No child nodes , and then look for the node with the inquiry relationship, found that 6 with its inquiry relationship, and vis[6]=1, so LCA (6,7) =find (6)= 4. End and Mark Vis[7]=1,pre[7]=4;
- Now node 4 has been searched, and there is no inquiry relationship with the node, vis[4]=1,pre[4]=2;
- Search 5, found that it has child nodes 8, search 8, found 8 No child nodes, and then look for the node with a query relationship, and then return, and vis[5]=1,pre[8]=5;
- node 5 has been searched and found two nodes that have a relationship with them 6 and 7, and vis[6]=1, so LCA (5,6) =find (6)= 2; because vis[7]=1, so LCA (5,7) =find (7)= 2; Loop finished return, Mark vis[5]=1,pre[5]=2; (find procedure: pre[7]=4-->pre[4]=2 = = "2, very standard one and check set Lookup representative meta action)
- node 2 has been searched, found that there is a query relationship with the node 7, and Vis[7]=1, so LCA (2,7) =find (7)= 2. Traverse complete, Mark Vis[2]=1,pre[2]=1;
- Then search 3, No child nodes, found that there is a query with the node 5, because vis[5]=1, so LCA (3,5) =find (5) =1 ; Traverse end, Mark Vis[3]=1,pre[3]=1; (Find procedure: Pre[5]=2-->pre[2]=1 = = "1)
- At this point back to the node 1, it has no inquiry relationship with the points, and its pre[1]=1, the search is over.
This completes the operation to find the smallest common ancestor.
Iv. Code Templates
Due to the ever-changing subject of LCA, the following is the most basic template (given a series of side tables to save, the query is also saved with adjacency table, only for LCA, do not maintain other values)
void Tarjan (int now) { vis[now]=1; for (int i=head1[now];i!=-1;i=e1[i].next) { int t=e1[i].t; if (vis[t]==0) { Tarjan (t); Join (now,t); } } for (int i=head2[now];i!=-1;i=e2[i].next) { int t=e2[i].t; if (vis[t]==1) { e2[i].lca=find (t); E2[i^1].lca=e2[i].lca;}}}
V. Training of the Battlefield
Title: POJ 1470
Code:
/* * POJ 1470 * Give a forward tree, Q query * Output query results per point occurrences//* * LCA offline algorithm, Tarjan * complexity O (n+q); */Const int MAXN = 1010; const int MAXQ = 500010;//The maximum of the number of queries//and the check set part int f[maxn];//needs to be initialized to-1 int find (int x) {if (f[x] = = 1) return x; return f[x] = find (f[x]); } void Bing (int u,int v) {int T1 = find (u); int t2 = Find (v); if (t1! = t2) F[t1] = t2; }//************************ bool vis[maxn];//access tag int ancestor[maxn];//ancestor struct Edge {int to,next;} EDGE[MAXN*2]; int Head[maxn],tot; void Addedge (int u,int v) {edge[tot].to = v; Edge[tot].next = Head[u]; Head[u] = tot++; } struct Query {int q,next; int index;//query number}query[maxq*2]; The int answer[maxq];//stores the final query result, subscript 0~q-1 int H[MAXQ]; int tt; int Q; void add_query (int u,int v,int index) {query[tt].q = v; Query[tt].next = H[u]; Query[tt].index = index; H[u] = tt++; QUERY[TT].Q = u; 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,false,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) {int v = edge[i].to; if (Vis[v]) continue; LCA (v); Bing (U,V); Ancestor[find (u)] = u; } for (int i = h[u];i! = -1;i = query[i].next) {int v = query[i].q; if (Vis[v]) {Answer[query[i].index] = Ancestor[find (v)]; }}} bool FLAG[MAXN]; int Count_num[maxn];int Main () {int n; int u,v,k; while (scanf ("%d", &n) = = 1) {init (); memset (flag,false,sizeof (flag)); for (int i = 1;i <= n;i++) {scanf ("%d: (%d)", &u,&k); while (k--) {scanf ("%d", &v); FLAG[V] = true; Addedge (U,V); Addedge (V,u); }} scanf ("%d", &q); for (int i = 0;i < q;i++) {char ch; cin>>ch; scanf ("%d%d)", &u,&v); Add_query (U,v,i); } int root; for (int i = 1;i <= n;i++) if (!flag[i]) {root = i; Break } LCA (root); memset (count_num,0,sizeof (count_num)); for (int i = 0;i < q;i++) count_num[answer[i]]++; for (int i = 1;i <= n;i++) if (Count_num[i] > 0) printf ("%d:%d\n", I,count_num[i]); } return 0; }
LCA (recent public ancestor)-Offline Tarjan algorithm