VOOZH about

URL: https://www.geeksforgeeks.org/dsa/counting-segment-inversions-of-an-array-with-updates/

⇱ Counting segment inversions of an Array with updates - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Counting segment inversions of an Array with updates

Last Updated : 23 Jul, 2025

Given an array of small integers arr[] and a 2D array of queries[][], In each query array we have the first element indicating the operation type, and the remaining elements are the arguments.

  • If query[i][0] is '1' then query[i][1] = l and query[i][2] = r and we have to Find the number of inversions in the segment from l to r (inclusive) of the array and print the result.
  • If query[i][0] is '2' then query[i][1] = idx and query[i][2] = v and we have to change the element at index idx of the array to value v.

Examples:

Input: arr[] = {1, 2, 3, 6, 5, 4} , queries={{1, 1, 3}, {1, 2, 5}, {2, 2, 8}, {1, 1, 4}}
Output: 0 1 2
Explanation:

  • In the first query, there are no inversions in segment [1, 3], so the output is 0.
  • In the second query, there is one inversion in segment [2, 5]: (6, 5), so the output is 1.
  • In the third query, the Type of the query is 2 so arr is changed to {1 8 3 6 5 4}.
  • In the final query, there are now two inversions in segment [1, 4]: (8,3), (8, 6), so the output is 2.

Naïve Approach: The basic way to solve the problem is as follows:

For operation Type 1, we can use two nested for loops to check for each pair of elements and count the number of them that form an inversion. Then, for operation Type 2, we simply assign the given value to arr[i].

Time Complexity: O(n2)
Auxiliary Space: O(n)

Efficient Approach: To solve the problem follow the below idea:

We can use a Segment tree to optimize the segment queries, while maintaining a good time complexity in updates.

Steps to solve the problem:

  • Create a Segment Tree for each node and Store two information on each segment node:
    • The number of inversions on the segment.
    • A frequency array, where freq[i] represents number of times i appears on the segment.
  • For single element segments, we have that the number of inversions is 0 and the frequency array is filled with 0s, having 1 only on the index of its value. For bigger segments, we use a merge function.
  • Given that we are merging the left and right nodes into the parent node, we have the following:
    • Each entry of the frequency array of the parent node will be the sum of that entry on each of the child nodes: parent.freq[i] = left.freq[i] + right.freq[i]
    • The number of inversions will be the sum of the inversions on each node plus the number of inversions between the two nodes. We assume we already have the two first numbers, so we only need to calculate the third.
  • In Merge function: for each element in V, there is an inversion whenever they are present in the left node and there are smaller elements present on the right node. This means we can write two nested loops and sum to the inversions counter the product of the frequency of the bigger element on the left times the frequency of the smaller element on the right: this calculation can be optimized using a prefix sum array.
  • Having an algorithm to merge two child nodes of the segment tree on a parent node, we only need to implement the query and the update functions.
    • Query function will be a typical query implementation for segment trees, using a node with number of inversions and all entries in frequency array equal to 0 as a "neutral" operand of the merge function.
    • Update function will be pretty standard as well. When we find the node of segment [idx, idx], we change its frequency array accordingly and update the parent nodes through recursion. We can either set all the frequency array entries to 0 and change freq[v] to 1 or maintain the current state of the array and update just the previous value entry to 0, because we know all other entries are 0 already.
  • With this approach, we first spend O(n) building the segment tree with its initial values and O(logn) for both operations, resulting in a total time complexity of O(n + q*logn), where q is the number of queries.

Below is the implementation of the above idea:


Output
0
1
2

Time Complexity: O(n + q*logn)
Auxiliary Space: O(n)

Comment
Article Tags: