# Min-Max Range Queries in Array

Given an array arr[0 . . . n-1]. We need to efficiently find the minimum and maximum value from index qs (query start) to qe (query end) where 0 <= qs <= qe <= n-1. We are given multiple queries.

Examples:

```Input : arr[] = {1, 8, 5, 9, 6, 14, 2, 4, 3, 7}
queries = 5
qs = 0 qe = 4
qs = 3 qe = 7
qs = 1 qe = 6
qs = 2 qe = 5
qs = 0 qe = 8
Output: Minimum = 1 and Maximum = 9
Minimum = 2 and Maximum = 14
Minimum = 2 and Maximum = 14
Minimum = 5 and Maximum = 14
Minimum = 1 and Maximum = 14
```

## Recommended: Please try your approach on {IDE} first, before moving on to the solution.

Simple Solution : We solve this problem using Tournament Method for each query. Complexity for this approach will be O(queries * n).

Efficient solution : This problem can be solved more efficiently by using Segment Tree. First read given segment tree link then start solving this problem.

```// C++ program to find minimum and maximum using segment tree
#include<bits/stdc++.h>
using namespace std;

// Node for storing minimum nd maximum value of given range
struct node
{
int minimum;
int maximum;
};

// A utility function to get the middle index from corner indexes.
int getMid(int s, int e) {  return s + (e -s)/2;  }

/*  A recursive function to get the minimum and maximum value in
a given range of array indexes. The following are parameters
for this function.

st    --> Pointer to segment tree
index --> Index of current node in the segment tree. Initially
0 is passed as root is always at index 0
ss & se  --> Starting and ending indexes of the segment
represented  by current node, i.e., st[index]
qs & qe  --> Starting and ending indexes of query range */
struct node MaxMinUntill(struct node *st, int ss, int se, int qs,
int qe, int index)
{
// If segment of this node is a part of given range, then return
//  the minimum and maximum node of the segment
struct node tmp,left,right;
if (qs <= ss && qe >= se)
return st[index];

// If segment of this node is outside the given range
if (se < qs || ss > qe)
{
tmp.minimum = INT_MAX;
tmp.maximum = INT_MIN;
return tmp;
}

// If a part of this segment overlaps with the given range
int mid = getMid(ss, se);
left = MaxMinUntill(st, ss, mid, qs, qe, 2*index+1);
right = MaxMinUntill(st, mid+1, se, qs, qe, 2*index+2);
tmp.minimum = min(left.minimum, right.minimum);
tmp.maximum = max(left.maximum, right.maximum);
return tmp;
}

// Return minimum and maximum of elements in range from index
// qs (quey start) to qe (query end).  It mainly uses
// MaxMinUtill()
struct node MaxMin(struct node *st, int n, int qs, int qe)
{
struct node tmp;

// Check for erroneous input values
if (qs < 0 || qe > n-1 || qs > qe)
{
printf("Invalid Input");
tmp.minimum = INT_MIN;
tmp.minimum = INT_MAX;
return tmp;
}

return MaxMinUntill(st, 0, n-1, qs, qe, 0);
}

// A recursive function that constructs Segment Tree for array[ss..se].
// si is index of current node in segment tree st
void constructSTUtil(int arr[], int ss, int se, struct node *st,
int si)
{
// If there is one element in array, store it in current node of
// segment tree and return
if (ss == se)
{
st[si].minimum = arr[ss];
st[si].maximum = arr[ss];
return ;
}

// If there are more than one elements, then recur for left and
// right subtrees and store the minimum and maximum of two values
// in this node
int mid = getMid(ss, se);
constructSTUtil(arr, ss, mid, st, si*2+1);
constructSTUtil(arr, mid+1, se, st, si*2+2);

st[si].minimum = min(st[si*2+1].minimum, st[si*2+2].minimum);
st[si].maximum = max(st[si*2+1].maximum, st[si*2+2].maximum);
}

/* Function to construct segment tree from given array. This function
allocates memory for segment tree and calls constructSTUtil() to
fill the allocated memory */
struct node *constructST(int arr[], int n)
{
// Allocate memory for segment tree

// Height of segment tree
int x = (int)(ceil(log2(n)));

// Maximum size of segment tree
int max_size = 2*(int)pow(2, x) - 1;

struct node *st = new struct node[max_size];

// Fill the allocated memory st
constructSTUtil(arr, 0, n-1, st, 0);

// Return the constructed segment tree
return st;
}

// Driver program to test above functions
int main()
{
int arr[] = {1, 8, 5, 9, 6, 14, 2, 4, 3, 7};
int n = sizeof(arr)/sizeof(arr[0]);

// Build segment tree from given array
struct node *st = constructST(arr, n);

int qs = 0;  // Starting index of query range
int qe = 8;  // Ending index of query range
struct node result=MaxMin(st, n, qs, qe);

// Print minimum and maximum value in arr[qs..qe]
printf("Minimum = %d and Maximum = %d ",
result.minimum, result.maximum);

return 0;
}
```

Output:

```Minimum = 1 and Maximum = 14
```

Time Complexity : O(queries * logn)

Can we do better if there are no updates on array?
The above segment tree based solution also allows array updates also to happen in O(Log n) time. Assume a situation when there are no updates (or array is static). We can actually process all queries in O(1) time with some preprocessing. One simple solution is to make a 2D table of nodes that stores all range minimum and maximum. This solution requires O(1) query time, but requires O(n2) preprocessing time and O(n2) extra space which can be a problem for large n. We can solve this problem in O(1) query time, O(n Log n) space and O(n Log n) preprocessing time using Sparse Table.

# GATE CS Corner    Company Wise Coding Practice

Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.
4 Average Difficulty : 4/5.0
Based on 4 vote(s)