Segment tree

For solving the RMQ problem we can also use segment trees. A segment tree is a heap-like data structure that can be used for making update/query operations upon array intervals in logarithmical time. We define the segment tree for the interval [i, j] in the following recursive manner: the first node will hold the information for the interval [i, j] if i<j the left and right son will hold the information for the intervals [i, (i+j)/2] and [(i+j)/2+1, j] Notice that the height of a segment tree for an interval with N elements is [logN] + 1. Here is how a segment tree for the interval [0, 9] would look like:

The segment tree has the same structure as a heap, so if we have a node numbered x that is not a leaf the left son of x is 2*x and the right son 2*x+1.

For solving the RMQ problem using segment trees we should use an array M[1, 2 * 2[logN] + 1] where M[i] holds the minimum value position in the interval assigned to node i. At the beginning all elements in M should be -1. The tree should be initialized with the following function (b and e are the bounds of the current interval):

void initialize(intnode, int b, int e, int M[MAXIND], int A[MAXN], int N) { if (b == e)         M[node] = b;      else { //compute the values in the left and right subtrees initialize(2 * node, b, (b + e) / 2, M, A, N); initialize(2 * node + 1, (b + e) / 2 + 1, e, M, A, N); //search for the minimum value in the first and //second half of the interval if (A[M[2 * node]] <= A[M[2 * node + 1]]) M[node] = M[2 * node]; else M[node] = M[2 * node + 1]; } } The function above reflects the way the tree is constructed. When calculating the minimum position for some interval we should look at the values of the sons. You should call the function with node = 1, b = 0 and e = N-1.

We can now start making queries. If we want to find the position of the minimum value in some interval [i, j] we should use the next easy function: int query(int node, int b, int e, int M[MAXIND], int A[MAXN], int i, int j) { int p1, p2;

//if the current interval doesn't intersect //the query interval return -1 if (i > e || j < b)         return -1; //if the current interval is included in  //the query interval return M[node] if (b >= i && e <= j)         return M[node]; //compute the minimum position in the //left and right part of the interval p1 = query(2 * node, b, (b + e) / 2, M, A, i, j); p2 = query(2 * node + 1, (b + e) / 2 + 1, e, M, A, i, j); //return the position where the overall //minimum is     if (p1 == -1) return M[node] = p2; if (p2 == -1) return M[node] = p1; if (A[p1] <= A[p2]) return M[node] = p1; return M[node] = p2;

} You should call this function with node = 1, b = 0 and e = N - 1, because the interval assigned to the first node is [0, N-1].

It's easy to see that any query is done in O(log N). Notice that we stop when we reach completely in/out intervals, so our path in the tree should split only one time.

Using segment trees we get an  algorithm. Segment trees are very powerful, not only because they can be used for RMQ. They are a very flexible data structure, can solve even the dynamic version of RMQ problem, and have numerous applications in range searching problems.