Open In App

Working and need of Mo’s Algorithm

Last Updated : 02 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Mo’s Algorithm is a generic algorithm. It can be used in many problems that require processing range queries in a static array, i.e., the array values do not change between the queries. In each query, for a given range [a, b] the idea is to calculate the value based on the array elements between positions of a and b. Since the array is static, the queries can be processed in any order, and Mo’s Algorithm processes the queries in a special order which guarantees that the algorithm works efficiently.

It maintains an active range of the array, and the result of a query concerning the active range is known at each moment. The algorithm processes the queries one by one, and always moves the endpoints of the active range by inserting and removing elements.

Time Complexity: O(N√N*f(N)), where the array has N elements and there are N queries and each insertion and removal of an element takes O(f(N)) time.

The trick in Mo’s algorithm is the order in which the queries are processed:

  • The array is divided into blocks of k = O(√N) elements, and a query [a1, b1] is processed before a query [a2, b2] if either [a1/k] < [a2/k] or [a1/k] = [a2/k] and b1 < b2 is true.
  • Thus, all queries whose left endpoints are in a certain block are processed one after another sorted according to their right endpoints.
  • Using this order, the algorithm only performs O(N√N) operations, because of the left endpoint moves O(N) times O(√N) steps, and the right endpoint moves O(√N) times O(N) steps.
  • Thus, both endpoints move a total of O(N√N) steps during the algorithm.

Example: Consider a problem where there are given a set of queries, each of them corresponding to a range in an array, and the task is to calculate for each query the number of distinct elements in the range. In Mo’s algorithm, the queries are always sorted in the same way, but it depends on the problem of how the answer to the query is maintained. 

  • In this problem, the idea is to maintain an array count[] where count[x] indicates the number of times an element x occurs in the active range.
  • When moving from one query to another query, the active range changes.  For example, if the current range is {4, 2, 5, 4, 2, 4, 3, 3, 4} and the next range is {4, 2, 5, 4, 2, 4, 3, 3, 4}. (ranges are marked as bold)
  • There will be three steps: the left endpoint moves one step to the right, and the right endpoint moves two steps to the right.
  • After each step, the array count[] needs to be updated.
  • After adding an element x, increase the value of count[x] by 1, and if the count[x] = 1 after this also increase the answer to the query by 1.
  • Similarly, after removing an element x, decrease the value of count[x] by 1, and if the count[x] = 0 after this, also decrease the answer to the query by 1.
  • In this problem, the time needed to perform each step is O(1), so the total time complexity of the algorithm is O(N√N).

Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads