MO's Algorithm Introduction

Last Updated : 19 Feb, 2026

Mo’s Algorithm can be explained using the range sum query problem, where an array and several queries are given. Each query contains a range [L,R][L, R][L,R], and we need to calculate the sum of elements within that range.

Example:

Input: arr[] = {1, 1, 2, 1, 3, 4, 5, 2, 8}, Query = [0, 4], [1, 3], [2, 4]
Output: Sum of arr[] elements in range [0, 4] is 8
Sum of arr[] elements in range [1, 3] is 4
Sum of arr[] elements in range [2, 4] is 6
Explanation:
Query [0, 4] - 1 + 1 + 2 + 1 + 3 = 8
Query [1, 3] - 1 + 2 + 1 = 4
Query [2, 4] - 2 + 1 + 3 = 6

Try It Yourself
redirect icon

[Naive Approach] – Linearly Compute Sum for Every Query – O(n × m) Time and O(1) Space

For each query [L,R][L, R][L,R], traverse the array from index L to R and compute the sum of elements in that range. Repeat this process for every query.

C++
#include <iostream>
using namespace std;

// Structure to represent a query range
struct Query
{
    int L, R;
};

// Prints sum of all query ranges. m is number of queries
// n is the size of the array.
void printQuerySums(int arr[], int n, Query q[], int m)
{
    for (int i = 0; i < m; i++)
    {
        int L = q[i].L, R = q[i].R;

        int sum = 0;
        for (int j = L; j <= R; j++)
            sum += arr[j];

        cout << "Sum of [" << L << ", " << R << "] is " << sum << endl;
    }
}

int main()
{
    int arr[] = {1, 1, 2, 1, 3, 4, 5, 2, 8};
    int n = sizeof(arr) / sizeof(arr[0]);

    Query q[] = {{0, 4}, {1, 3}, {2, 4}};
    int m = sizeof(q) / sizeof(q[0]);

    printQuerySums(arr, n, q, m);
    return 0;
}
Java
import java.util.*;
 
// Class to represent a query range 
class Query{ 
    int L; 
    int R; 
    Query(int L, int R){
        this.L = L;
        this.R = R;
    }
} 

class GFG
{
    // Prints sum of all query ranges. m is number of queries
    // n is the size of the array.
    static void printQuerySums(int arr[], int n, ArrayList<Query> q, int m)
    {
        // One by one compute sum of all queries
        for (int i=0; i<m; i++)
        {
            // Left and right boundaries of current range
            int L = q.get(i).L, R = q.get(i).R;
    
            // Compute sum of current query range
            int sum = 0;
            for (int j=L; j<=R; j++)
                sum += arr[j];
    
            // Print sum of current query range
            System.out.println("Sum of [" + L +
                           ", " + R + "] is "  + sum);
        }
    }
    
    public static void main(String argv[])
    {
        int arr[] = {1, 1, 2, 1, 3, 4, 5, 2, 8};
        int n = arr.length;
        
        ArrayList<Query> q = new ArrayList<Query>();
        q.add(new Query(0,4));
        q.add(new Query(1,3));
        q.add(new Query(2,4));
        
        int m = q.size();
        printQuerySums(arr, n, q, m);
    }
}
Python
# Function to compute and print sum of each query
def print_query_sum(arr, queries):

    # Traverse through each query
    for q in queries:
        L, R = q
        s = 0

        # Compute sum of current query range
        for i in range(L, R + 1):
            s += arr[i]

        # Print result
        print("Sum of", q, "is", s)


if __name__ == "__main__":

    # Input array
    arr = [1, 1, 2, 1, 3, 4, 5, 2, 8]

    # Query ranges
    queries = [[0, 4], [1, 3], [2, 4]]

    # Function call
    print_query_sum(arr, queries)
C#
using System;
using System.Collections;
  
// Class to represent a query range 
public class Query
{
    public int L; 
    public int R; 
    
    public Query(int L, int R)
    {
        this.L = L;
        this.R = R;
    }
} 
 
class GFG{
    
    // Prints sum of all query ranges. m 
    //is number of queries n is the size 
    // of the array.
    static void printQuerySums(int []arr, int n, 
                           ArrayList q, int m)
    {
        
        // One by one compute sum of all queries
        for(int i = 0; i < m; i++)
        {
            
            // Left and right boundaries of 
            // current range
            int L = ((Query)q[i]).L,
                R = ((Query)q[i]).R;
     
            // Compute sum of current query range
            int sum = 0;
            for(int j = L; j <= R; j++)
                sum += arr[j];
                
            // Print sum of current query range
            Console.Write("Sum of [" + L + ", " +
                          R + "] is " + sum + "\n");
        }
    }
     
    public static void Main(string []argv)
    {
        int []arr = { 1, 1, 2, 1, 3, 4, 5, 2, 8 };
        int n = arr.Length;
        
        ArrayList q = new ArrayList();
        q.Add(new Query(0, 4));
        q.Add(new Query(1, 3));
        q.Add(new Query(2, 4));
         
        int m = q.Count;
        
        printQuerySums(arr, n, q, m);
    }
}
JavaScript
using System;
using System.Collections;
  
// Class to represent a query range 
public class Query
{
    public int L; 
    public int R; 
    
    public Query(int L, int R)
    {
        this.L = L;
        this.R = R;
    }
} 
 
class GFG{
    
    // Prints sum of all query ranges. m 
    //is number of queries n is the size 
    // of the array.
    static void printQuerySums(int []arr, int n, 
                           ArrayList q, int m)
    {
        
        // One by one compute sum of all queries
        for(int i = 0; i < m; i++)
        {
            
            // Left and right boundaries of 
            // current range
            int L = ((Query)q[i]).L,
                R = ((Query)q[i]).R;
     
            // Compute sum of current query range
            int sum = 0;
            for(int j = L; j <= R; j++)
                sum += arr[j];
                
            // Print sum of current query range
            Console.Write("Sum of [" + L + ", " +
                          R + "] is " + sum + "\n");
        }
    }
     
    public static void Main(string []argv)
    {
        int []arr = { 1, 1, 2, 1, 3, 4, 5, 2, 8 };
        int n = arr.Length;
        
        ArrayList q = new ArrayList();
        q.Add(new Query(0, 4));
        q.Add(new Query(1, 3));
        q.Add(new Query(2, 4));
         
        int m = q.Count;
        
        printQuerySums(arr, n, q, m);
    }
}

Output
Sum of [0, 4] is 8
Sum of [1, 3] is 4
Sum of [2, 4] is 6

[Expected Approach] – MO’s Algorithm – O((n + m) × √n) Time and O(n + m) Space

The idea of MO's algorithm is to pre-process all queries so that result of one query can be used in next query. Below are steps.

Steps of MO’s Algorithm

  • Divide the array into blocks of size √n.
  • Sort the queries by the block number of L, and within the same block, sort them by R in increasing order.
  • Process the queries one by one while maintaining a running sum.
  • Let sum represent the result of the previous query; if the new query has a larger R, add the new elements, and if it has a smaller L, remove the extra elements.
  • Update the sum incrementally instead of recomputing it from scratch.
C++
#include <iostream>
using namespace std;

// Variable to represent block size. This is made global
// so compare() of sort can use it.
int block;

// Structure to represent a query range
struct Query
{
    int L, R;
};

// Function used to sort all queries so that all queries 
// of the same block are arranged together and within a block,
// queries are sorted in increasing order of R values.
bool compare(Query x, Query y)
{
    // Different blocks, sort by block.
    if (x.L/block != y.L/block)
        return x.L/block < y.L/block;

    // Same block, sort by R value
    return x.R < y.R;
}

// Prints sum of all query ranges. m is number of queries
// n is size of array a[].
void queryResults(int a[], int n, Query q[], int m)
{
    // Find block size
    block = (int)sqrt(n);

    // Sort all queries so that queries of same blocks
    // are arranged together.
    sort(q, q + m, compare);

    // Initialize current L, current R and current sum
    int currL = 0, currR = 0;
    int currSum = 0;

    // Traverse through all queries
    for (int i=0; i<m; i++)
    {
        // L and R values of current range
        int L = q[i].L, R = q[i].R;

        // Remove extra elements of previous range. For
        // example if previous range is [0, 3] and current
        // range is [2, 5], then a[0] and a[1] are subtracted
        while (currL < L)
        {
            currSum -= a[currL];
            currL++;
        }

        // Add Elements of current Range
        while (currL > L)
        {
            currSum += a[currL-1];
            currL--;
        }
        while (currR <= R)
        {
            currSum += a[currR];
            currR++;
        }

        // Remove elements of previous range.  For example
        // when previous range is [0, 10] and current range
        // is [3, 8], then a[9] and a[10] are subtracted
        while (currR > R+1)
        {
            currSum -= a[currR-1];
            currR--;
        }

        // Print sum of current range
        cout << "Sum of [" << L << ", " << R
             << "] is "  << currSum << endl;
    }
}

int main()
{
    int a[] = {1, 1, 2, 1, 3, 4, 5, 2, 8};
    int n = sizeof(a)/sizeof(a[0]);
    Query q[] = {{0, 4}, {1, 3}, {2, 4}};
    int m = sizeof(q)/sizeof(q[0]);
    queryResults(a, n, q, m);
    return 0;
}
Java
import java.util.*;

// Class to represent a query range 
class Query{ 
    int L; 
    int R; 
    Query(int L, int R){
        this.L = L;
        this.R = R;
    }
} 

class GFG{

    // Prints sum of all query ranges. m is number of queries 
    // n is size of array a[]. 
    static void queryResults(int a[], int n, ArrayList<Query> q, int m){
        
        // Find block size 
        int block = (int) Math.sqrt(n); 
    
        // Sort all queries so that queries of same blocks 
        // are arranged together.
        Collections.sort(q, new Comparator<Query>(){
            
            // Function used to sort all queries so that all queries  
            // of the same block are arranged together and within a block, 
            // queries are sorted in increasing order of R values. 
            public int compare(Query x, Query y){

                // Different blocks, sort by block. 
                if (x.L/block != y.L/block) 
                    return (x.L < y.L ? -1 : 1); 

                // Same block, sort by R value 
                return (x.R < y.R ? -1 : 1);
            }
        });

        // Initialize current L, current R and current sum 
        int currL = 0, currR = 0; 
        int currSum = 0; 
    
        // Traverse through all queries 
        for (int i=0; i<m; i++) 
        { 
            // L and R values of current range
            int L = q.get(i).L, R = q.get(i).R; 

            // Remove extra elements of previous range. For 
            // example if previous range is [0, 3] and current 
            // range is [2, 5], then a[0] and a[1] are subtracted 
            while (currL < L) 
            { 
                currSum -= a[currL]; 
                currL++; 
            } 

            // Add Elements of current Range 
            while (currL > L) 
            { 
                currSum += a[currL-1]; 
                currL--; 
            } 
            while (currR <= R) 
            { 
                currSum += a[currR]; 
                currR++; 
            } 

            // Remove elements of previous range.  For example 
            // when previous range is [0, 10] and current range 
            // is [3, 8], then a[9] and a[10] are subtracted 
            while (currR > R+1) 
            { 
                currSum -= a[currR-1]; 
                currR--; 
            } 

            // Print sum of current range 
            System.out.println("Sum of [" + L +
                           ", " + R + "] is "  + currSum); 
        } 
    }

    public static void main(String argv[]){
        ArrayList<Query> q = new ArrayList<Query>();
        q.add(new Query(0,4));
        q.add(new Query(1,3));
        q.add(new Query(2,4));

        int a[] = {1, 1, 2, 1, 3, 4, 5, 2, 8}; 
        queryResults(a, a.length, q, q.size()); 
    }
}
Python
import math

# Function that accepts array and list of queries
# and prints sum of each query
def query_results(arr, queries):

    # Sort all queries in increasing order of R
    queries.sort(key=lambda x: x[1])

    # Initialize current L, current R and current sum
    currL, currR, currSum = 0, 0, 0

    # Traverse through all queries
    for q in queries:
        L, R = q

        # Remove extra elements from previous range
        while currL < L:
            currSum -= arr[currL]
            currL += 1

        # Add elements when moving left boundary backward
        while currL > L:
            currSum += arr[currL - 1]
            currL -= 1

        # Add elements of current range
        while currR <= R:
            currSum += arr[currR]
            currR += 1

        # Remove elements when right boundary shrinks
        while currR > R + 1:
            currSum -= arr[currR - 1]
            currR -= 1

        # Print the result
        print("Sum of", q, "is", currSum)


if __name__ == "__main__":

    arr = [1, 1, 2, 1, 3, 4, 5, 2, 8]
    queries = [[0, 4], [1, 3], [2, 4]]

    query_results(arr, queries)
C#
using System;
using System.Collections.Generic;

class GFG
{
  
  // Variable to represent block size. This is made global
  // so compare() of sort can use it.
  public static int block;

  // Structure to represent a query range
  public struct Query
  {
    public int L;
    public int R;
    public Query(int l, int r)
    {
      L = l;
      R = r;
    }
  }

  // Function used to sort all queries so that all queries
  // of the same block are arranged together and within a
  // block, queries are sorted in increasing order of R
  // values.
  public class Comparer : IComparer<Query> {
    public int Compare(Query x, Query y)
    {
      int ret = (int)(x.L / block)
        .CompareTo((int)(y.L / block));
      return ret != 0 ? ret : x.R.CompareTo(y.R);
    }
  }

  // Prints sum of all query ranges. m is number of
  // queries n is size of array a[].
  static void queryResults(int[] a, int n, List<Query> q,
                           int m)
  {
    // Find block size
    block = (int)(Math.Sqrt(n));

    // Sort all queries so that queries of same blocks
    // are arranged together.
    q.Sort(new Comparer());

    // Initialize current L, current R and current sum
    int currL = 0, currR = 0;
    int currSum = 0;

    // Traverse through all queries
    for (int i = 0; i < m; i++) {
      // L and R values of current range
      int L = q[i].L, R = q[i].R;

      // Remove extra elements of previous range. For
      // example if previous range is [0, 3] and
      // current range is [2, 5], then a[0] and a[1]
      // are subtracted
      while (currL < L) {
        currSum -= a[currL];
        currL++;
      }

      // Add Elements of current Range
      while (currL > L) {
        currSum += a[currL - 1];
        currL--;
      }
      while (currR <= R) {
        currSum += a[currR];
        currR++;
      }

      // Remove elements of previous range. For
      // example when previous range is [0, 10] and
      // current range is [3, 8], then a[9] and a[10]
      // are subtracted
      while (currR > R + 1) {
        currSum -= a[currR - 1];
        currR--;
      }

      // Print sum of current range
      Console.WriteLine("Sum of [{0}, {1}] is {2}", L,
                        R, currSum);
    }
  }

  static void Main(string[] args)
  {
    int[] a = { 1, 1, 2, 1, 3, 4, 5, 2, 8 };
    int n = a.Length;
    List<Query> q = new List<Query>();
    q.Add(new Query(0, 4));
    q.Add(new Query(1, 3));
    q.Add(new Query(2, 4));
    int m = q.Count;
    queryResults(a, n, q, m);
  }
}
JavaScript
function queryResults(arr, Q) {
  // Sort all queries so that all queries in the increasing order of R values
  Q.sort((a, b) => a[1] - b[1]);

  // Initialize current L, current R and current sum
  let currL = 0;
  let currR = 0;
  let currSum = 0;

  // Traverse through all queries
  for (let i = 0; i < Q.length; i++) {
    const L = Q[i][0];
    const R = Q[i][1];

    // Remove extra elements from previous range
    // if previous range is [0, 3] and current
    // range is [2, 5], then a[0] and a[1] are subtracted
    while (currL < L) {
      currSum -= arr[currL];
      currL++;
    }

    // Add elements of current range
    while (currL > L) {
      currSum += arr[currL - 1];
      currL--;
    }
    while (currR <= R) {
      currSum += arr[currR];
      currR++;
    }

    // Remove elements of previous range
    // when previous range is [0, 10] and current range
    // is [3, 8], then a[9] and a[10] are subtracted
    while (currR > R + 1) {
      currSum -= arr[currR - 1];
      currR--;
    }

    // Print the sum of current range
    console.log(`Sum of ${Q[i]} is ${currSum}`);
  }
}

const arr = [1, 1, 2, 1, 3, 4, 5, 2, 8];
const Q = [[1, 3], [0, 4], [2, 4]];
queryResults(arr, Q);

Output
Sum of [1, 3] is 4
Sum of [0, 4] is 8
Sum of [2, 4] is 6

Note: The results may not appear in the same order as the input queries because the queries are sorted. This can be handled by storing original indices.

Why It Works Efficiently

Because queries are sorted in blocks:

  • The pointer for R moves at most O(n × √n) times.
  • The pointer for L moves at most O(m × √n) times.

Time Complexity

  • Sorting queries: O(m log m)
  • Processing queries: O((n + m) × √n)
  • Overall: O((n + m) × √n)

Space Complexity

  • Storing array and queries - O(n + m)

Important Observations: 

  • All queries must be known beforehand so they can be preprocessed.
  • It does not work efficiently when update operations are mixed with queries.
  • It is suitable for problems where each query result can be derived from the previous one (e.g., sum, minimum, maximum).

Note: A simple and more Efficient solution to solve this problem is to compute prefix sum for all elements from 0 to n-1. Let the prefix sum be stored in an array preSum[] (The value of preSum[i] stores sum of arr[0..i]). Once we have built preSum[], we can traverse through all queries one by one. For every query [L, R], we return value of preSum[R] - preSum[L]. Here processing every query takes O(1) time. 

Comment