Download - RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
1/17
Range Minimum Query and Lowest
Common AncestorBy danielp– TopCoder Member
Introduction
The problem of finding the Lowest Common Ancestor (LCA) of a pair of nodes in a
rooted tree has been studied more carefully in the second part of the 20th century
and now is fairly basic in algorithmic graph theory. This problem is interesting not
only for the tricy algorithms that can be used to sol!e it" but for its numerous
applications in string processing and computational biology" for e#ample" whereLCA is used with suffi# trees or other tree$lie structures. %arel and Tar&an were the
first to study this problem more attenti!ely and they showed that after linear
preprocessing of the input tree LCA" 'ueries can be answered in constant time.
Their wor has since been e#tended" and this tutorial will present many interesting
approaches that can be used in other inds of problems as well.
Lets consider a less abstract e#ample of LCA the tree of life. Its a well$nown fact
that the current habitants of *arth e!ol!ed from other species. This e!ol!ing
structure can be represented as a tree" in which nodes represent species" and thesons of some node represent the directly e!ol!ed species. +ow species with similar
characteristics are di!ided into groups. ,y finding the LCA of some nodes in this
tree we can actually find the common parent of two species" and we can determine
that the similar characteristics they share are inherited from that parent.
-ange inimum /uery (-/) is used on arrays to find the position of an element
with the minimum !alue between two specified indices. e will see later that the
LCA problem can be reduced to a restricted !ersion of an -/ problem" in which
consecuti!e array elements differ by e#actly 1.
%owe!er" -/s are not only used with LCA. They ha!e an important role in string
preprocessing" where they are used with suffi# arrays (a new data structure that
supports string searches almost as fast as suffi# trees" but uses less memory and
less coding effort).
In this tutorial we will first tal about -/. e will present many approaches that
sol!e the problem some slower but easier to code" and others faster. In thesecond part we will tal about the strong relation between LCA and -/. 3irst we
https://www.topcoder.com/member-profile/danielphttp://www.topcoder.com/tc?module=LinkTracking&link=http://siamdl.aip.org/getabs/servlet/GetabsServlet?prog=normal%26id=SMJCAT000013000002000338000001%26idtype=cvips%26gifs=Yes&refer=http://www.topcoder.com/tc?module=LinkTracking&link=http://siamdl.aip.org/getabs/servlet/GetabsServlet?prog=normal%26id=SMJCAT000013000002000338000001%26idtype=cvips%26gifs=Yes&refer=http://www.topcoder.com/tc?module=LinkTracking&link=http://siamdl.aip.org/getabs/servlet/GetabsServlet?prog=normal%26id=SMJCAT000013000002000338000001%26idtype=cvips%26gifs=Yes&refer=https://www.topcoder.com/member-profile/danielp
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
2/17
will re!iew two easy approaches for LCA that dont use -/4 then show that the
-/ and LCA problems are e'ui!alent4 and" at the end" well loo at how the -/
problem can be reduced to its restricted !ersion" as well as show a fast algorithm
for this particular case.
+otations
5uppose that an algorithm has preprocessing time f(n) and 'uery time g(n). The
notation for the o!erall comple#ity for the algorithm is .
e will note the position of the element with the minimum !alue in some
array A between indices i and j withRMQA(i, j).
The furthest node from the root that is an ancestor of both u and v in some rooted
tree T is LCAT(u, v).
-ange inimum /uery(-/)6i!en an array A[0, N-1] find the position of the element with the minimum !alue
between two gi!en indices.
Tri!ial algorithms for -/3or e!ery pair of indices (i, j) store the !alue of RMQA(i, j) in a table M[0, N-1][0, N-
1]. Tri!ial computation will lead us to an comple#ity. %owe!er" by
using an easy dynamic programming approach we can reduce the comple#ity
to . The preprocessing function will loo something lie this
void process1(int M[MAXN][MAXN], int A[MAXN], int N)
{
int i, j;
for (i =0; i < N; i++)
M[i][i] = i;
for (i = 0; i < N; i++)
for (j = i + 1; j < N; j++)
if (A[M[i][j - 1]] < A[j])
M[i][j] = M[i][j - 1];
else
M[i][j] = j;
}
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
3/17
This tri!ial algorithm is 'uite slow and uses O(N2) memory" so it wont wor for largecases.
An 78(+)" 8(s'rt(+))9 solution
An interesting idea is to split the !ector in sq!(N) pieces. e will eep in a
!ector M[0, sq!(N)-1] the position for the minimum !alue for each section. M canbe easily preprocessed in O(N). %ere is an e#ample
+ow lets see how can we compute RMQA(i, j). The idea is to get the o!erallminimum from the sq!(N)sections that lie inside the inter!al" and from the end andthe beginning of the first and the last sections that intersect the bounds of theinter!al. To get RMQA(2,") in the abo!e e#ample we shouldcompare A[2]"A[M[1]]" A[#] and A["] and get the position of the minimum !alue.Its easy to see that this algorithm doesnt mae more than 3 $ sq!(N) operationsper 'uery.
The main ad!antages of this approach are that is to 'uic to code (a plus for
TopCoder$style competitions) and that you can adapt it to the dynamic !ersion of
the problem (where you can change the elements of the array between 'ueries).
5parse Table (5T) algorithm
A better approach is to preprocess RMQ for sub arrays of length 2% using dynamic
programming. e will eep an array M[0, N-1][0, &'gN] where M[i][j] is the inde# of
the minimum !alue in the sub array starting at iha!ing length 2 j. %ere is an
e#ample
3or computing M[i][j] we must search for the minimum !alue in the first and second
half of the inter!al. Its ob!ious that the small pieces ha!e 2 j 1
length" so therecurrence is
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
4/17
The preprocessing function will loo something lie this
void process2(int M[MAXN][LOGMAXN], int A[MAXN], int N)
{
int i, j;
i!i"i#$i%e M &or "'e i!"er#$s i"' $e!*"' 1
for (i = 0; i < N; i++)
M[i][0] = i;
cop"e #$es &ro s#$$er "o i**er i!"er#$s for (j = 1; 1
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
5/17
The segment tree has the same structure as a heap" so if we ha!e a node
numbered . that is not a leaf the left son of . is 2$. and the right son 2$.+1.
3or sol!ing the -/ problem using segment trees we should use an array M[1, 2 $
2[&'gN] + 1] where M[i] holds the minimum !alue position in the inter!al assigned to
node i. At the beginning all elements in M should be -1. The tree should be
initiali;ed with the following function (/ and are the bounds of the current
inter!al)
void i!i"i#$i%e(int!o.e, int , int e, int M[MAX/N],int A[MAXN], int N)
{
if ( == e)
M[!o.e] = ;
else
{
cop"e "'e #$es i! "'e $e&" #!. ri*'" s"rees
i!i"i#$i%e(2 !o.e, , ( + e) 2, M, A, N);
i!i"i#$i%e(2 !o.e + 1, ( + e) 2 + 1, e, M,
A, N);
se#rc' &or "'e i!i #$e i! "'e &irs" #!.
seco!. '#$& o& "'e i!"er#$
if (A[M[2 !o.e]]
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
6/17
}
The function abo!e reflects the way the tree is constructed. hen calculating theminimum position for some inter!al we should loo at the !alues of the sons.
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
7/17
algorithm. 5egment trees are !erypowerful" not only because they can be used for -/. They are a !ery fle#ible data
structure" can sol!e e!en the dynamic !ersion of -/ problem" and ha!e
numerous applications in range searching problems.
Lowest Common Ancestor (LCA)
6i!en a rooted tree T and two nodes u and v, find the furthest node from the root
that is an ancestor for bothu and v. %ere is an e#ample (the root of the tree will be
node 1 for all e#amples in this editorial)
An 78(+)" 8(s'rt(+))9 solution
>i!iding our input into e'ual$si;ed parts pro!es to be an interesting way to sol!e
the -/ problem. This method can be adapted for the LCA problem as well. The
idea is to split the tree in sq!() parts" were is the height of the tree. Thus" the
first section will contain the le!els numbered from 0 !' sq!() 1" the second will
contain the le!els numbered from sq!() !' 2 $ sq!() 1" and so on. %ere ishow the tree in the e#ample should be di!ided
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
8/17
+ow" for each node" we should now the ancestor that is situated on the last le!el
of the upper ne#t section. e will preprocess this !alues in an array [1, MA4N].
%ere is how should loo lie for the tree in the e#ample (for simplity" for e!ery
node i in the first section let [i] * 1)
+otice that for the nodes situated on the le!els that are the first ones in some
sections" [i] * T[i]. e can preprocess using a depth first search (T[i] is the
father of node i in the tree" n is [sq!()] and L[i] is the le!el of the node i)
void .&s(int !o.e, int 8[MAXN], int N, int 9[MAXN], int
L[MAXN], int !r) {
int :;
i& !o.e is si"#"e. i! "'e &irs"
sec"io! "'e! P[node] = 1
i& !o.e is si"#"e. #" "'e e*i!!i!*
o& soe sec"io! "'e! P[node] = T[node]
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
9/17
i& !o!e o& "'ose "o c#ses occrs, "'e!
P[node] = P[T[node]]
if (L[!o.e] < !r)
9[!o.e] = 1;
else
if((L[!o.e] !r))
9[!o.e] = 8[!o.e];
else
9[!o.e] = 9[8[!o.e]];
for e#c' so! : o& !o.e
.&s(:, 8, N, 9, L, !r); }
+ow" we can easily mae 'ueries. 3or finding LCA(., 5) we we will first find in whatsection it lays" and then tri!ially compute it. %ere is the code
i!" LA(int 8[MAXN], int 9[MAXN], int L[MAXN], int >,
int 3)
{
#s $o!* #s "'e !o.e i! "'e !e>" sec"io! o&
> #!. 3 is !o" o!e coo! #!ces"or
e *e" "'e !o.e si"#"e. o! "'e s#$$er
$eer c$oser
while (9[>] = 9[3])
if (L[>] 5 L[3])
> = 9[>];
else
3 = 9[3];
!o "'e3 #re i! "'e s#e sec"io!, so e "rii#$$3
cop"e "'e LA
while (> = 3)
if (L[>] 5 L[3])
> = 8[>];
else
3 = 8[3];
return >;
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
10/17
}
This function maes at most 2 $ sq!() operations. =sing this approach we getan algorithm" where is the height of the tree. In the worst
case * N" so the o!erall comple#ity is . The main ad!antageof this algorithm is 'uic coding (an a!erage >i!ision 1 coder shouldnt need morethan 1? minutes to code it).
Another easy solution in 78(+ log+" 8(log+)9
If we need a faster solution for this problem we could use dynamic programming.
3irst" lets compute a table @1"+B1"log+B where @iB&B is the 2 &$th ancestor of i. 3or
computing this !alue we may use the following recursion
The preprocessing function should loo lie this
void process?(int N, int 8[MAXN], int 9[MAXN][LOGMAXN])
{
int i, j;
e i!i"i#$i%e eer3 e$ee!" i! 9 i"' -1
for (i = 0; i < N; i++)
for (j = 0; 1
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
11/17
searching for LCA(6 * [6][j], q * [q][j]). At the end" both 6 and q will ha!e thesame father" so return T[6]. Lets see what happens if L[6] 7* L[q]. Assume"without loss of generality" that L[6] < L[q]. e can use the same meta$binarysearch for finding the ancestor of 6 situated on the same le!el with q" and then wecan compute the LCA as described below. %ere is how the 'uery function should
loo
int er3(int N, int 9[MAXN][LOGMAXN], int 8[MAXN],
int L[MAXN], int p, int )
{
int "p, $o*, i;
i& p is si"#"e. o! # 'i*'er $ee$ "'#! "'e! e s#p
"'e
if (L[p] < L[])
"p = p, p = , = "p;
e cop"e "'e #$e o& [$o*(L[p)]
for ($o* = 1; 1
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
12/17
algorithm is . This solution is easy to code too" and its fasterthan the pre!ious one.
-eduction from LCA to -/
+ow" lets show how we can use -/ for computing LCA 'ueries. Actually" we will
reduce the LCA problem to -/ in linear time" so e!ery algorithm that sol!es the-/ problem will sol!e the LCA problem too. Lets show how this reduction can be
done using an e#ample
clic to enlarge image
+otice that LCAT(u, v) is the closest node from the root encountered between the
!isits of u and v during a depth first search of T. 5o" we can consider all nodes
between any two indices of u and v in the *uler Tour of the tree and then find the
node situated on the smallest le!el between them. 3or this" we must build three
arrays
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
13/17
• 8[1, 2$N-1] the nodes !isited in an *uler Tour of T4 8[i] is the label of i-
!9 !isited node in the tour
• L[1, 2$N-1] the le!els of the nodes !isited in the *uler Tour4 L[i] is the le!el
of node 8[i]
• [1, N] [i] is the inde# of the first occurrence of node i in 8 (any
occurrence would be good" so its not bad if we consider the first one) Assume that [u] < [v] (otherwise you must swap u and v). Its easy to see thatthe nodes between the first occurrence of u and the first occurrence of v are 8[[u]:[v]]. +ow" we must find the node situated on the smallest le!el. 3or this" we canuse RMQ. 5o" LCAT(u, v) * 8[RMQL([u], [v])] (remember that -/ returns theinde#). %ere is how 8" L and should loo for the e#ample
clic to enlarge image+otice that consecuti!e elements in L differ by e#actly 1.
3rom -/ to LCA
e ha!e shown that the LCA problem can be reduced to -/ in linear time. %ere
we will show how we can reduce the -/ problem to LCA. This means that we
actually can reduce the general -/ to the restricted !ersion of the problem
(where consecuti!e elements in the array differ by e#actly 1). 3or this we should
use cartesian trees.
A Cartesian Tree of an array A[0, N - 1] is a binary tree C(A) whose root is a
minimum element of A" labeled with the position i of this minimum. The left child of
the root is the Cartesian Tree of A[0, i - 1] if i > 0" otherwise theres no child. The
right child is defined similary for A[i + 1, N - 1]. +ote that the Cartesian Tree is not
necessarily uni'ue if A contains e'ual elements. In this tutorial the first appearance
of the minimum !alue will be used" thus the Cartesian Tree will be uni'ue. Its easy
to see now that RMQA(i, j) * LCAC(i, j).
%ere is an e#ample
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
14/17
+ow we only ha!e to compute C(A) in linear time. This can be done using a stac.
At the beginning the stac is empty. e will then insert the elements of A in the
stac. At the i-!9 step A[i] will be added ne#t to the last element in the stac that
has a smaller or e'ual !alue to A[i]" and all the greater elements will be remo!ed.
The element that was in the stac on the position of A[i] before the insertion was
done will become the left son of i" and A[i] will become the right son of the smaller
element behind him. At e!ery step the first element in the stac is the root of the
cartesian tree. Its easier to build the tree if the stac will hold the inde#es of the
elements" and not their !alue.
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
15/17
%ere is how the stac will loo at each step for the e#ample abo!e
Step Stack Modifications made in the tree
0 0 0 is the only node in the tree.
1 0 1
1 is added at the end of the stack.
Now, 1 is the right son of 0.
2 0 2
2 is added next to 0, and 1 is
removed (!2" # !1"$. Now, 2 is the
right son of 0 and the left son of 2 is
1.
% %
!%" is the smallest element in the
vector so far, so all elements in the
stack will &e removed and % will
&ecome the root of the tree. 'he left
child of % is 0.
%
is added next to %, and the right son
of % is .
) % )
) is added next to , and the right son
of is ).
* % ) *
* is added next to ), and the right son
of ) is *.
+
% ) *
+
+ is added next to *, and the right son
of * is +.
%
is added next to %, and all greater
elements are removed. is now the
right child of % and the left child of
is .
- % -
- is added next to , and the right son
of is -.
+ote that e!ery element in A is only added once and remo!ed at most once" so thecomple#ity of this algorithm is O(N). %ere is how the tree$processing function willloo
void cop"e8ree(int A[MAXN], int N, int 8[MAXN]) {
int s"[MAXN], i, :, "op = -1;
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
16/17
e s"#r" i"' #! ep"3 s"#c:
#" s"ep i e i!ser" A[i] i! "'e s"#c:
for (i = 0; i < N; i++)
{
cop"e "'e posi"io! o& "'e &irs" e$ee!" "'#" is
e#$ or s#$$er "'#! A[i]
: = "op;
while (: 5= 0 77 A[s"[:]] 5 A[i])
:--;
e o.i&3 "'e "ree #s e>p$#i!e. #oe
if (: = -1)
8[i] = s"[:]; if (: < "op)
8[s"[: + 1]] = i;
e i!ser" A[i] i! "'e s"#c: #!. reoe
#!3 i**er e$ee!"s
s"[++:] = i;
"op = :;
}
"'e &irs" e$ee!" i! "'e s"#c: is "'e roo" o&
"'e "ree, so i" '#s !o "'er
8[s"[0]] = -1;
}
An78(+)" 8(1)9 algorithm for the restricted -/+ow we now that the general -/ problem can be reduced to the restricted!ersion using LCA. %ere" consecuti!e elements in the array differ by e#actly 1. ecan use this and gi!e a fast algorithm. 3rom now we will sol!e the-/ problem for an array A[0, N - 1] where ;A[i] A[i + 1]; * 1" i * [1, N - 1]. etransform A in a binary array with N-1 elements" where A[i] * A[i] A[i + 1]. Itsob!ious that elements in A can be &ust +1 or -1. +otice that the old !alue of A[i] isnow the sum of A[1]" A[2] .. A[i] plus the old A[0]. %owe!er" we wont need the old!alues from now on.
To sol!e this restricted !ersion of the problem we need to partition A into blocs of
si;e & * [(&'g N) 2]. LetA[i] be the minimum !alue for the i-!9 bloc
in A and =[i] be the position of this minimum !alue in A. ,oth Aand = are N& long.
+ow" we preprocess A using the 5T algorithm described in 5ection1. This will
tae O(N& $ &'g(N&)) * O(N) time and space. After this preprocessing we can mae
'ueries that span o!er se!eral blocs in O(1). It remains now to show how the in$
-
8/20/2019 RangRange Minimum Query and Lowest Common Ancestore Minimum Query and Lowest Common Ancestor
17/17
bloc 'ueries can be made. +ote that the length of a bloc is & * [(&'g N) 2]" which
is 'uite small. Also" note that A is a binary array. The total number of binary arrays
of si;e &is 2&*sq!(N). 5o" for each binary bloc of si;e & we need to loc up in a
table the !alue for -/ between e!ery pair of indices. This can be tri!ially
computed in O(sq!(N)$&2)*O(N) time and space. To inde# table " preprocess the
type of each bloc in A and store it in array T[1, N&]. The bloc type is a binary
number obtained by replacing $1 with 0 and D1 with 1.
+ow" to answer RMQA(i, j) we ha!e two cases
• i and j are in the same bloc" so we use the !alue computed in and T
• i and j are in different blocs" so we compute three !alues the minimum
from i to the end of isbloc using and T" the minimum of all blocs
between is and &s bloc using precomputed 'ueries on A and the minimum from
the begining of js bloc to j" again using T and 4 finally return the position where
the o!erall minimum is using the three !alues you &ust computed.Conclusion-/ and LCA are strongly related problems that can be reduced one to another.any algorithms can be used to sol!e them" and they can be adapted to other indof problems as well.
%ere are some training problems for segment trees" LCA and -/