Range GCD Queries

Last Updated : 17 Dec, 2025

Given an array arr[] and a series of queries q[][]. Each query can be one of the following two types:

  • Update query: 1 index value — Update the element at position index to value.
  • GCD query: 2 L R — Find the GCD of all elements in the range [L, R] (both inclusive).

We need to process all the queries in order and return a vector of integers containing the results of all GCD queries.

Examples:

Input: arr[] = [2, 3, 4, 6, 8, 16], q[][]= [[2, 0, 2], [1, 3, 8], [2, 2, 5]]
Output: [1, 4]
Explanation:
Query [2, 0, 2] -> GCD of elements in range [0, 2] -> gcd(2,3,4) = 1
Query [1, 3, 8] -> Update arr[3] = 8 -> array becomes [2,3,4,8,8,16]
Query [2, 2, 5] -> GCD of elements in range [2,5] -> gcd(4,8,8,16) = 4

Input: arr[] = [12, 15, 18, 24, 30], q[][]= [[2, 0, 3], [1, 2, 6], [2, 1, 4]]
Output: [3, 3]
Explanation:
Query [2, 0, 3] -> GCD of elements in range [0, 3] -> gcd(12,15,18,24) = 3
Query [1, 2, 6] -> Update arr[2] = 6 -> array becomes [12,15,6,24,30]
Query [2, 1, 4] -> GCD of elements in range [1, 4] -> gcd(15,6,24,30) = 3

[Approach 1] Iterative GCD - O(q x n) Time and O(n) Space

The approach is to process the array sequentially for each query. For a GCD query, we iterate through the specified range of the array and maintain a variable to store the running GCD. At each step, we update this variable by computing the GCD of the current value and the next element in the range. For an updateValue query, we directly modify the array at the specified index with the new value. By handling the queries in order, each type-2 query operates on the most up-to-date state of the array.

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

// Function to compute GCD of two numbers
int gcd(int a, int b) {
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

// Function to find GCD of elements in range [l, r]
int findRangeGcd(int l, int r, vector<int>& arr) {
    int res = arr[l];
    for (int i = l + 1; i <= r; i++) {
        res = gcd(res, arr[i]);
    }
    return res;
}

// Process all queries and return results of type-2 queries
vector<int> processQueries(vector<int>& arr, vector<vector<int>>& q) {
    vector<int> result;

    for (auto &query : q) {
        int type = query[0];

        if (type == 1) {
            int index = query[1];
            int new_val = query[2];
            arr[index] = new_val;  // Update value
        } 
        else { // type 2
            int l = query[1];
            int r = query[2];
            result.push_back(findRangeGcd(l, r, arr));
        }
    }

    return result;
}

int main() {
    vector<int> arr = {2, 3, 4, 6, 8, 16};

    vector<vector<int>> q = {
        {2, 0, 2},  // find GCD from index 0 to 2
        {1, 3, 8},  // update index 3 to 8
        {2, 2, 5}   // find GCD from index 2 to 5
    };

    vector<int> ans = processQueries(arr, q);

    for (int x : ans) {
        cout << x << " ";
    }

    return 0;
}
Java
import java.util.ArrayList;

public class GFG {
    // Function to compute GCD of two numbers
    public static int gcd(int a, int b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }

    // Function to find GCD of elements in range [l, r]
    public static int findRangeGcd(int l, int r, int[] arr) {
        int res = arr[l];
        for (int i = l + 1; i <= r; i++) {
            res = gcd(res, arr[i]);
        }
        return res;
    }

    // Process all queries and return results of type-2 queries
    public static ArrayList<Integer> processQueries(int[] arr, int[][] q) {
        ArrayList<Integer> result = new ArrayList<>();

        for (int[] query : q) {
            int type = query[0];

            if (type == 1) {
                int index = query[1];
                int new_val = query[2];
                arr[index] = new_val; // Update value
            } else { // type 2
                int l = query[1];
                int r = query[2];
                result.add(findRangeGcd(l, r, arr));
            }
        }

        return result;
    }

    public static void main(String[] args) {
        int[] arr = {2, 3, 4, 6, 8, 16};
        int[][] q = {
            {2, 0, 2},  // find GCD from index 0 to 2
            {1, 3, 8},  // update index 3 to 8
            {2, 2, 5}   // find GCD from index 2 to 5
        };

        ArrayList<Integer> ans = processQueries(arr, q);

        for (int x : ans) System.out.print(x + " ");
    }
}
Python
from math import gcd

# Function to find GCD of elements in range [l, r]
def findRangeGcd(l, r, arr):
    res = arr[l]
    for i in range(l + 1, r + 1):
        res = gcd(res, arr[i])
    return res

# Process all queries and return results of type-2 queries
def processQueries(arr, q):
    result = []

    for query in q:
        type_ = query[0]

        if type_ == 1:
            index, new_val = query[1], query[2]
            arr[index] = new_val  # Update value
        else:
            l, r = query[1], query[2]
            result.append(findRangeGcd(l, r, arr))
    return result

if __name__ == "__main__":
    arr = [2, 3, 4, 6, 8, 16]
    q = [
        [2, 0, 2],  # find GCD from index 0 to 2
        [1, 3, 8],  # update index 3 to 8
        [2, 2, 5]   # find GCD from index 2 to 5
    ]
    
    ans = processQueries(arr, q)
    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG {
    // Function to compute GCD of two numbers
    static int gcd(int a, int b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }

    // Function to find GCD of elements in range [l, r]
    static int findRangeGcd(int l, int r, int[] arr) {
        int res = arr[l];
        for (int i = l + 1; i <= r; i++) {
            res = gcd(res, arr[i]);
        }
        return res;
    }

    // Process all queries and return results of type-2 queries
    static List<int> processQueries(int[] arr, int[][] q) {
        List<int> result = new List<int>();

        foreach (var query in q) {
            int type = query[0];

            if (type == 1) {
                int index = query[1];
                int new_val = query[2];
                arr[index] = new_val;  // Update value
            } else { // type 2
                int l = query[1];
                int r = query[2];
                result.Add(findRangeGcd(l, r, arr));
            }
        }

        return result;
    }

    static void Main() {
        int[] arr = {2, 3, 4, 6, 8, 16};
        int[][] q = {
            new int[]{2, 0, 2},
            new int[]{1, 3, 8},
            new int[]{2, 2, 5}
        };

        List<int> ans = processQueries(arr, q);

        foreach (var x in ans) Console.Write(x + " ");
    }
}
JavaScript
// Function to compute GCD of two numbers
function gcd(a, b) {
    if (b === 0) return a;
    return gcd(b, a % b);
}

// Function to find GCD of elements in range [l, r]
function findRangeGcd(l, r, arr) {
    let res = arr[l];
    for (let i = l + 1; i <= r; i++) {
        res = gcd(res, arr[i]);
    }
    return res;
}

// Process all queries and return results of type-2 queries
function processQueries(arr, q) {
    const result = [];

    for (let query of q) {
        const type = query[0];

        if (type === 1) {
            const index = query[1];
            const new_val = query[2];
            arr[index] = new_val; // Update value
        } else { // type 2
            const l = query[1];
            const r = query[2];
            result.push(findRangeGcd(l, r, arr));
        }
    }

    return result;
}

// Example usage
const arr = [2, 3, 4, 6, 8, 16];
const q = [
    [2, 0, 2],  // find GCD from index 0 to 2
    [1, 3, 8],  // update index 3 to 8
    [2, 2, 5]   // find GCD from index 2 to 5
];

const ans = processQueries(arr, q);
console.log(ans.join(" "));

Output
1 4

[Approach 2] Segment Tree for Range GCD - O((n + q) log(n)) Time and O(n) Space

Instead of repeatedly scanning the array for every GCD query, we first preprocess the array using a segment tree, where each node stores the GCD of a sub-range.

  • For a GCD query (findRangeGCD), we only look at the segments that overlap with the query range, and combine their GCD values. This avoids checking every element individually.
  • For an update query (updateValue), we change the value at the given index and then recompute the GCDs only along the path from that index up to the root of the segment tree. This ensures the rest of the tree remains unchanged and allows future queries to remain efficient.

This approach drastically reduces the number of operations compared to scanning the array every time, making both queries and updates much faster, especially for large arrays.

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

// Function to compute GCD of two numbers
int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

// Get mid index
int getMid(int s, int e) {
    return s + (e - s) / 2;
}

// Build segment tree
int buildSegmentTree(vector<int>& arr, int ss, int se, vector<int>& st, int si) {
    if (ss == se) {
        st[si] = arr[ss];
        return arr[ss];
    }
    int mid = getMid(ss, se);
    st[si] = gcd(
        buildSegmentTree(arr, ss, mid, st, si*2 + 1),
        buildSegmentTree(arr, mid+1, se, st, si*2 + 2)
    );
    return st[si];
}

// Query GCD in range
int findGcd(int ss, int se, int qs, int qe, int si, vector<int>& st) {
    if (ss > qe || se < qs) return 0; // neutral for GCD
    if (qs <= ss && qe >= se) return st[si];
    int mid = getMid(ss, se);
    return gcd(
        findGcd(ss, mid, qs, qe, 2*si + 1, st),
        findGcd(mid+1, se, qs, qe, 2*si + 2, st)
    );
}

// Update a value in segment tree
void updateValueUtil(int ss, int se, int index, int new_val, int si, vector<int>& st) {
    if (index < ss || index > se) return;
    if (ss == se) {
        st[si] = new_val;
        return;
    }
    int mid = getMid(ss, se);
    if (index <= mid)
        updateValueUtil(ss, mid, index, new_val, 2*si + 1, st);
    else
        updateValueUtil(mid+1, se, index, new_val, 2*si + 2, st);
    st[si] = gcd(st[2*si + 1], st[2*si + 2]);
}

// Wrapper to update value
void updateValue(int index, int new_val, vector<int>& arr, vector<int>& st, int n) {
    arr[index] = new_val;
    updateValueUtil(0, n-1, index, new_val, 0, st);
}

// Function to process queries
vector<int> processQueries(vector<int>& arr, vector<vector<int>>& q) {
    int n = arr.size();
    int x = 2 * (int)pow(2, ceil(log2(n))) - 1;
    vector<int> st(x);
    buildSegmentTree(arr, 0, n-1, st, 0);

    vector<int> result;
    for (auto &query : q) {
        int type = query[0];
        if (type == 1) {
            int index = query[1];
            int new_val = query[2];
            updateValue(index, new_val, arr, st, n);
        } else { // type 2
            int l = query[1];
            int r = query[2];
            result.push_back(findGcd(0, n-1, l, r, 0, st));
        }
    }
    return result;
}

int main() {
    vector<int> arr = {2, 3, 4, 6, 8, 16};
    vector<vector<int>> q = {
        {2, 0, 2},  // find GCD from index 0 to 2
        {1, 3, 8},  // update index 3 to 8
        {2, 2, 5}   // find GCD from index 2 to 5
    };

    vector<int> ans = processQueries(arr, q);

    for (int x : ans) cout << x << " ";
    cout << "\n";

    return 0;
}
Java
import java.util.ArrayList;

public class GFG {

    // Function to compute GCD of two numbers
    static int gcd(int a, int b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }

    // Get mid index
    static int getMid(int s, int e) {
        return s + (e - s) / 2;
    }

    // Build segment tree
    static int buildSegmentTree(int[] arr, int ss, int se, int[] st, int si) {
        if (ss == se) {
            st[si] = arr[ss];
            return arr[ss];
        }
        int mid = getMid(ss, se);
        st[si] = gcd(
            buildSegmentTree(arr, ss, mid, st, si * 2 + 1),
            buildSegmentTree(arr, mid + 1, se, st, si * 2 + 2)
        );
        return st[si];
    }

    // Query GCD in range
    static int findGcd(int ss, int se, int qs, int qe, int si, int[] st) {
        if (ss > qe || se < qs) return 0; // neutral for GCD
        if (qs <= ss && qe >= se) return st[si];
        int mid = getMid(ss, se);
        return gcd(
            findGcd(ss, mid, qs, qe, 2 * si + 1, st),
            findGcd(mid + 1, se, qs, qe, 2 * si + 2, st)
        );
    }

    // Update a value in segment tree
    static void updateValueUtil(int ss, int se, int index, int new_val, int si, int[] st) {
        if (index < ss || index > se) return;
        if (ss == se) {
            st[si] = new_val;
            return;
        }
        int mid = getMid(ss, se);
        if (index <= mid)
            updateValueUtil(ss, mid, index, new_val, 2 * si + 1, st);
        else
            updateValueUtil(mid + 1, se, index, new_val, 2 * si + 2, st);
        st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }

    // Wrapper to update value
    static void updateValue(int index, int new_val, int[] arr, int[] st, int n) {
        arr[index] = new_val;
        updateValueUtil(0, n - 1, index, new_val, 0, st);
    }

    // Process queries
    static ArrayList<Integer> processQueries(int[] arr, int[][] q) {
        int n = arr.length;
        int x = 2 * (int) Math.pow(2, Math.ceil(Math.log(n) / Math.log(2))) - 1;
        int[] st = new int[x];
        buildSegmentTree(arr, 0, n - 1, st, 0);

        ArrayList<Integer> result = new ArrayList<>();
        for (int i = 0; i < q.length; i++) {
            int type = q[i][0];
            if (type == 1) {
                int index = q[i][1];
                int new_val = q[i][2];
                updateValue(index, new_val, arr, st, n);
            } else {
                int l = q[i][1];
                int r = q[i][2];
                result.add(findGcd(0, n - 1, l, r, 0, st));
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[] arr = {2, 3, 4, 6, 8, 16};
        int[][] q = {
            {2, 0, 2},  // find GCD from index 0 to 2
            {1, 3, 8},  // update index 3 to 8
            {2, 2, 5}   // find GCD from index 2 to 5
        };

        ArrayList<Integer> ans = processQueries(arr, q);
        for (int x : ans) System.out.print(x + " ");
    }
}
Python
import math
from typing import List

# Function to compute GCD of two numbers
def gcd(a: int, b: int) -> int:
    if b == 0:
        return a
    return gcd(b, a % b)

# Get mid index
def getMid(s: int, e: int) -> int:
    return s + (e - s) // 2

# Build segment tree
def buildSegmentTree(arr: List[int], ss: int, se: int, st: List[int], si: int) -> int:
    if ss == se:
        st[si] = arr[ss]
        return arr[ss]
    mid = getMid(ss, se)
    st[si] = gcd(
        buildSegmentTree(arr, ss, mid, st, si*2 + 1),
        buildSegmentTree(arr, mid+1, se, st, si*2 + 2)
    )
    return st[si]

# Query GCD in range
def findGcd(ss: int, se: int, qs: int, qe: int, si: int, st: List[int]) -> int:
    if ss > qe or se < qs:
        return 0
    if qs <= ss and qe >= se:
        return st[si]
    mid = getMid(ss, se)
    return gcd(
        findGcd(ss, mid, qs, qe, 2*si + 1, st),
        findGcd(mid+1, se, qs, qe, 2*si + 2, st)
    )

# Update value in segment tree
def updateValueUtil(ss: int, se: int, index: int, new_val: int, si: int, st: List[int]):
    if index < ss or index > se:
        return
    if ss == se:
        st[si] = new_val
        return
    mid = getMid(ss, se)
    if index <= mid:
        updateValueUtil(ss, mid, index, new_val, 2*si + 1, st)
    else:
        updateValueUtil(mid+1, se, index, new_val, 2*si + 2, st)
    st[si] = gcd(st[2*si + 1], st[2*si + 2])

def updateValue(index: int, new_val: int, arr: List[int], st: List[int], n: int):
    arr[index] = new_val
    updateValueUtil(0, n-1, index, new_val, 0, st)

# Function to process queries
def processQueries(arr: List[int], q: List[List[int]]) -> List[int]:
    n = len(arr)
    x = 2 * int(2 ** math.ceil(math.log2(n))) - 1
    st = [0] * x
    buildSegmentTree(arr, 0, n-1, st, 0)

    result = []
    for query in q:
        type_ = query[0]
        if type_ == 1:
            index = query[1]
            new_val = query[2]
            updateValue(index, new_val, arr, st, n)
        else:
            l, r = query[1], query[2]
            result.append(findGcd(0, n-1, l, r, 0, st))
    return result

if __name__ == "__main__":
    arr = [2, 3, 4, 6, 8, 16]
    q = [
        [2, 0, 2],
        [1, 3, 8],
        [2, 2, 5]
    ]
    ans = processQueries(arr, q)
    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG
{
    // Function to compute GCD of two numbers
    static int gcd(int a, int b)
    {
        if (b == 0) return a;
        return gcd(b, a % b);
    }

    // Get mid index
    static int getMid(int s, int e)
    {
        return s + (e - s) / 2;
    }

    // Build segment tree
    static int buildSegmentTree(int[] arr, int ss, int se, int[] st, int si)
    {
        if (ss == se)
        {
            st[si] = arr[ss];
            return arr[ss];
        }
        int mid = getMid(ss, se);
        st[si] = gcd(
            buildSegmentTree(arr, ss, mid, st, si * 2 + 1),
            buildSegmentTree(arr, mid + 1, se, st, si * 2 + 2)
        );
        return st[si];
    }

    // Query GCD in range
    static int findGcd(int ss, int se, int qs, int qe, int si, int[] st)
    {
        if (ss > qe || se < qs) return 0; // neutral for GCD
        if (qs <= ss && qe >= se) return st[si];
        int mid = getMid(ss, se);
        return gcd(
            findGcd(ss, mid, qs, qe, 2 * si + 1, st),
            findGcd(mid + 1, se, qs, qe, 2 * si + 2, st)
        );
    }

    // Update value in segment tree
    static void updateValueUtil(int ss, int se, int index, int new_val, int si, int[] st)
    {
        if (index < ss || index > se) return;
        if (ss == se)
        {
            st[si] = new_val;
            return;
        }
        int mid = getMid(ss, se);
        if (index <= mid)
            updateValueUtil(ss, mid, index, new_val, 2 * si + 1, st);
        else
            updateValueUtil(mid + 1, se, index, new_val, 2 * si + 2, st);
        st[si] = gcd(st[2 * si + 1], st[2 * si + 2]);
    }

    // Wrapper to update value
    static void updateValue(int index, int new_val, int[] arr, int[] st, int n)
    {
        arr[index] = new_val;
        updateValueUtil(0, n - 1, index, new_val, 0, st);
    }

    // Process queries
    static List<int> processQueries(int[] arr, int[,] q)
    {
        int n = arr.Length;
        int x = 2 * (int)Math.Pow(2, Math.Ceiling(Math.Log(n, 2))) - 1;
        int[] st = new int[x];
        buildSegmentTree(arr, 0, n - 1, st, 0);

        List<int> result = new List<int>();
        for (int i = 0; i < q.GetLength(0); i++)
        {
            int type = q[i, 0];
            if (type == 1)
            {
                int index = q[i, 1];
                int new_val = q[i, 2];
                updateValue(index, new_val, arr, st, n);
            }
            else
            {
                int l = q[i, 1];
                int r = q[i, 2];
                result.Add(findGcd(0, n - 1, l, r, 0, st));
            }
        }
        return result;
    }

    static void Main()
    {
        int[] arr = { 2, 3, 4, 6, 8, 16 };
        int[,] q = {
            { 2, 0, 2 },
            { 1, 3, 8 },
            { 2, 2, 5 }
        };

        List<int> ans = processQueries(arr, q);
        Console.WriteLine(string.Join(" ", ans));
    }
}
JavaScript
// Function to compute GCD of two numbers
function gcd(a, b) {
    if (b === 0) return a;
    return gcd(b, a % b);
}

// Get mid index
function getMid(s, e) {
    return s + Math.floor((e - s) / 2);
}

// Build segment tree
function buildSegmentTree(arr, ss, se, st, si) {
    if (ss === se) {
        st[si] = arr[ss];
        return arr[ss];
    }
    let mid = getMid(ss, se);
    st[si] = gcd(
        buildSegmentTree(arr, ss, mid, st, si*2 + 1),
        buildSegmentTree(arr, mid+1, se, st, si*2 + 2)
    );
    return st[si];
}

// Query GCD in range
function findGcd(ss, se, qs, qe, si, st) {
    if (ss > qe || se < qs) return 0;
    if (qs <= ss && qe >= se) return st[si];
    let mid = getMid(ss, se);
    return gcd(
        findGcd(ss, mid, qs, qe, 2*si + 1, st),
        findGcd(mid+1, se, qs, qe, 2*si + 2, st)
    );
}

// Update value in segment tree
function updateValueUtil(ss, se, index, new_val, si, st) {
    if (index < ss || index > se) return;
    if (ss === se) {
        st[si] = new_val;
        return;
    }
    let mid = getMid(ss, se);
    if (index <= mid)
        updateValueUtil(ss, mid, index, new_val, 2*si + 1, st);
    else
        updateValueUtil(mid+1, se, index, new_val, 2*si + 2, st);
    st[si] = gcd(st[2*si + 1], st[2*si + 2]);
}

function updateValue(index, new_val, arr, st, n) {
    arr[index] = new_val;
    updateValueUtil(0, n-1, index, new_val, 0, st);
}

// Function to process queries
function processQueries(arr, q) {
    const n = arr.length;
    const x = 2 * Math.pow(2, Math.ceil(Math.log2(n))) - 1;
    const st = new Array(x);
    buildSegmentTree(arr, 0, n-1, st, 0);

    const result = [];
    for (let query of q) {
        const type = query[0];
        if (type === 1) {
            const [_, index, new_val] = query;
            updateValue(index, new_val, arr, st, n);
        } else {
            const [_, l, r] = query;
            result.push(findGcd(0, n-1, l, r, 0, st));
        }
    }
    return result;
}

// Example usage
const arr = [2, 3, 4, 6, 8, 16];
const q = [
    [2, 0, 2],
    [1, 3, 8],
    [2, 2, 5]
];
const ans = processQueries(arr, q);
console.log(ans.join(" "));

Output
1 4 
Comment