MO's Algorithm Introduction (original) (raw)

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 Yourselfredirect icon

Table of Content

[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 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 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

#include 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 { 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 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 q = new List(); 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 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>Q</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo></mrow><mi>i</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">{Q[i]} is </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mclose">]</span></span><span class="mord mathnormal">i</span><span class="mord mathnormal">s</span></span></span></span>{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:

**Time Complexity

**Space Complexity

**Important Observations:

**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.