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
Table of Content
- [Naive Approach] – Linearly Compute Sum for Every Query – O(n × m) Time and O(1) Space
- [Expected Approach] – MO’s Algorithm – O((n + m) × √n) Time and O(n + m) Space
[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
- 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 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:
- 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.