The idea is to pre-process the given array and break it down and represent it in the form of a tree.
For this question, two types of queries are needed - Update and COUNT_MIN_MAX.
- Update - We will insert the element in the segment tree. For this query, a subtree of the tree will be modified.
- COUNT_MIN_MAX - For the minimum and maximum query, we will iterate over the subtrees and count the number of nodes strictly smaller and greater. For this, some subtree or complete tree will be visited.
The data structure which provides these functionalities is known as a segment tree. It is also used for a number of queries like finding the sum, minimum, maximum, GCD, etc in log(N) time.
How to create the segment tree?
The segment tree is represented in the form of an array. Each node contains information answers for a range or subarray. For any index ‘i’(not a leaf node), its children are at index 2*i and 2*i + 1, respectively.
1. Build Segment tree/ Pre-processing:
- Declare an array 'SEGMENT_TREE' of size 4*N as 4*N size is enough to store all the nodes. It stores the number of elements in the given range.
- The bottom-up approach is used to build a segment tree. An iterative approach can also be used, but generally, the bottom-up approach is used. It takes O(N) time as we traverse each node exactly twice.
- But in this question, we have to count the number of elements strictly greater or smaller than the current element and then insert it in the segment tree. So, there is no need to build the segment tree. We will insert the elements in the update operation.
2. Update:
- Define a recursive function 'UPDATE' which takes 5 arguments 'SEGMENT_TREE', 'CURRENT_INDEX','VALUE', 'LOW', 'HIGH', that denotes the segment tree that we are cerating, the current index at which we are present, the VALUE that we have to insert, the lowest index, and the highest index for the current sub-segment tree.
- If 'LOW' is equal to 'HIGH', It means that it is the leaf node. So, increment SEGMENT_TREE[CURRENT_INDEX] by 1 and return.
- Find the middle of 'LOW' and 'HIGH' and store it in a variable 'MID'.
- If the 'VALUE' is greater than 'MID', call for the right sub-tree ie update(SEGMENT_TREE,2*CURRENT_INDEX + 1, VALUE, LOW, MID).
- Else call for the left sub tree ie. update(SEGMENT_TREE,2*CURRENT_INDEX + 2, VALUE, MID+1, HIGH).
- Now store the VALUE at the current index as the sum of its left and right children.
3. COUNT_MIN_MAX:
- Define a recursive function ‘COUNT_MIN_MAX’ which takes 5 arguments 'CURRENT_INDEX', 'LOW', 'HIGH',’l’, ‘h’, that denotes the current index of the node at which we are present, the lowest and highest node VALUEs for the current sub-segment tree, the range of VALUEs for which we are looking for. It returns an integer denoting the number of elements in the range l to r.
- If the range for which we are looking for completely lies inside the range of the current sub-segment tree. Return the VALUE of the current node as it should be included completely in the answer.
- If the range for which we are looking for completely lies outside the range of the current sub-segment tree, then return 0.
- Find the middle 'MID' of 'LOW' and 'HIGH' as the average of 'LOW' and 'HIGH'.
- Call for the left sub-segment tree for the same range that we are looking for i.e. COUNT_MIN_MAX(SEGMENT_TREE,2*CURRENT_INDEX + 1, LOW, MID, l, r) and store it in a variable 'LEFT_ANSWER'.
- Call for the right sub-segment tree for the same range that we are looking for i.e. COUNT_MIN_MAX(SEGMENT_TREE,2*CURRENT_INDEX + 2, MID+1, HIGH, l, r), and store it in a variable ‘RIGHT_ANSWER’.
- Return 'LEFT_ANSWER' + 'RIGHT_ANSWER' as the final answer.