📜  范围最小查询(平方根分解和稀疏表)

📅  最后修改于: 2021-04-17 13:03:30             🧑  作者: Mango

我们有一个数组arr [0。 。 。 n-1]。我们应该能够有效地找到从索引L(查询开始)到R(查询结束)的最小值,其中0 <= L <= R <= n-1 。考虑存在许多范围查询的情况。
例子:

Input:  arr[]   = {7, 2, 3, 0, 5, 10, 3, 12, 18};
        query[] = [0, 4], [4, 7], [7, 8]

Output: Minimum of [0, 4] is 0
        Minimum of [4, 7] is 3
        Minimum of [7, 8] is 12

一个简单的解决方案是运行一个从LR的循环,并找到给定范围内的最小元素。在最坏的情况下,此解决方案需要O(n)的时间进行查询。
另一种方法是使用Segment tree 。对于段树,预处理时间为O(n),到最小查询范围的时间为O(Logn) 。存储段树所需的额外空间为O(n)。段树也允许在O(Log n)时间进行更新。

如果我们知道数组是静态的,我们可以做得更好吗?

没有更新操作且范围最小查询很多时,如何优化查询时间?
以下是不同的方法。

方法1(简单解决方案)
一个简单的解决方案是创建一个2D数组lookup [] [],其中条目lookup [i] [j]将最小值存储在arr [i..j]范围内。现在可以在O(1)时间中计算给定范围的最小值。

rmqsimple

C++
// C++ program to do range
// minimum query in O(1) time with
// O(n*n) extra space and O(n*n)
// preprocessing time.
#include 
using namespace std;
#define MAX 500
 
// lookup[i][j] is going to store
// index of minimum value in
// arr[i..j]
int lookup[MAX][MAX];
 
// Structure to represent a query range
struct Query {
    int L, R;
};
 
// Fills lookup array lookup[n][n]
// for all possible values
// of query ranges
void preprocess(int arr[], int n)
{
    // Initialize lookup[][] for the
    // intervals with length 1
    for (int i = 0; i < n; i++)
        lookup[i][i] = i;
 
    // Fill rest of the entries in bottom up manner
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++)
 
            // To find minimum of [0,4],
            // we compare minimum
            // of arr[lookup[0][3]] with arr[4].
            if (arr[lookup[i][j - 1]] < arr[j])
                lookup[i][j] = lookup[i][j - 1];
            else
                lookup[i][j] = j;
    }
}
 
// Prints minimum of given m
// query ranges in arr[0..n-1]
void RMQ(int arr[], int n, Query q[], int m)
{
    // Fill lookup table for
    // all possible input queries
    preprocess(arr, n);
 
    // 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[i].L, R = q[i].R;
 
        // Print sum of current query range
        cout << "Minimum of [" << L
             << ", " << R << "] is "
             << arr[lookup[L][R]] << endl;
    }
}
 
// Driver code
int main()
{
    int a[] = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
    int n = sizeof(a) / sizeof(a[0]);
    Query q[] = { { 0, 4 }, { 4, 7 }, { 7, 8 } };
    int m = sizeof(q) / sizeof(q[0]);
    RMQ(a, n, q, m);
    return 0;
}


Java
// Java program to do range minimum query
// in O(1) time with O(n*n) extra space
// and O(n*n) preprocessing time.
import java.util.*;
 
class GFG {
    static int MAX = 500;
 
    // lookup[i][j] is going to store index of
    // minimum value in arr[i..j]
    static int[][] lookup = new int[MAX][MAX];
 
    // Structure to represent a query range
    static class Query {
        int L, R;
 
        public Query(int L, int R)
        {
            this.L = L;
            this.R = R;
        }
    };
 
    // Fills lookup array lookup[n][n] for
    // all possible values of query ranges
    static void preprocess(int arr[], int n)
    {
        // Initialize lookup[][] for
        // the intervals with length 1
        for (int i = 0; i < n; i++)
            lookup[i][i] = i;
 
        // Fill rest of the entries in bottom up manner
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++)
 
                // To find minimum of [0,4],
                // we compare minimum of
                // arr[lookup[0][3]] with arr[4].
                if (arr[lookup[i][j - 1]] < arr[j])
                    lookup[i][j] = lookup[i][j - 1];
                else
                    lookup[i][j] = j;
        }
    }
 
    // Prints minimum of given m query
    // ranges in arr[0..n-1]
    static void RMQ(int arr[], int n, Query q[], int m)
    {
        // Fill lookup table for
        // all possible input queries
        preprocess(arr, n);
 
        // 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[i].L, R = q[i].R;
 
            // Print sum of current query range
            System.out.println("Minimum of [" + L + ", " + R
                               + "] is "
                               + arr[lookup[L][R]]);
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int a[] = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
        int n = a.length;
        Query q[] = { new Query(0, 4), new Query(4, 7),
                      new Query(7, 8) };
        int m = q.length;
        RMQ(a, n, q, m);
    }
}
 
// This code is contributed by 29AjayKumar


Python3
# Python3 program to do range
# minimum query in O(1) time with
# O(n*n) extra space and O(n*n)
# preprocessing time.
MAX = 500
  
# lookup[i][j] is going to store
# index of minimum value in
# arr[i..j]
lookup = [[0 for j in range(MAX)]
             for i in range(MAX)]
  
# Structure to represent
# a query range
class Query:
     
    def __init__(self, L, R):
         
        self.L = L
        self.R = R
  
# Fills lookup array lookup[n][n]
# for all possible values
# of query ranges
def preprocess(arr, n):
 
    # Initialize lookup[][] for the
    # intervals with length 1
    for i in range(n):
        lookup[i][i] = i;
  
    # Fill rest of the entries in
    # bottom up manner
    for i in range(n):
        for j in range(i + 1, n):
  
            # To find minimum of [0,4],
            # we compare minimum
            # of arr[lookup[0][3]] with arr[4].
            if (arr[lookup[i][j - 1]] < arr[j]):
                lookup[i][j] = lookup[i][j - 1];
            else:
                lookup[i][j] = j;   
  
# Prints minimum of given m
# query ranges in arr[0..n-1]
def RMQ(arr, n, q, m):
 
    # Fill lookup table for
    # all possible input queries
    preprocess(arr, n);
  
    # One by one compute sum of
    # all queries
    for i in range(m):
 
        # Left and right boundaries
        # of current range
        L = q[i].L
        R = q[i].R;
  
        # Print sum of current query range
        print("Minimum of [" + str(L) + ", " +
               str(R) + "] is " +
               str(arr[lookup[L][R]]))
 
# Driver code
if __name__ == "__main__":
     
    a = [7, 2, 3, 0, 5,
         10, 3, 12, 18]
    n = len(a)   
    q = [Query(0, 4),
         Query(4, 7),
         Query(7, 8)]   
    m = len(q)   
    RMQ(a, n, q, m);
  
# This code is contributed by Rutvik_56


C#
// C# program to do range minimum query
// in O(1) time with O(n*n) extra space
// and O(n*n) preprocessing time.
using System;
 
class GFG {
    static int MAX = 500;
 
    // lookup[i][j] is going to store index of
    // minimum value in arr[i..j]
    static int[, ] lookup = new int[MAX, MAX];
 
    // Structure to represent a query range
    public class Query {
        public int L, R;
 
        public Query(int L, int R)
        {
            this.L = L;
            this.R = R;
        }
    };
 
    // Fills lookup array lookup[n][n] for
    // all possible values of query ranges
    static void preprocess(int[] arr, int n)
    {
        // Initialize lookup[][] for
        // the intervals with length 1
        for (int i = 0; i < n; i++)
            lookup[i, i] = i;
 
        // Fill rest of the entries in bottom up manner
        for (int i = 0; i < n; i++)
        {
            for (int j = i + 1; j < n; j++)
 
                // To find minimum of [0,4],
                // we compare minimum of
                // arr[lookup[0][3]] with arr[4].
                if (arr[lookup[i, j - 1]] < arr[j])
                    lookup[i, j] = lookup[i, j - 1];
                else
                    lookup[i, j] = j;
        }
    }
 
    // Prints minimum of given m query
    // ranges in arr[0..n-1]
    static void RMQ(int[] arr, int n, Query[] q, int m)
    {
        // Fill lookup table for
        // all possible input queries
        preprocess(arr, n);
 
        // 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[i].L, R = q[i].R;
 
            // Print sum of current query range
            Console.WriteLine("Minimum of [" + L + ", " + R
                              + "] is "
                              + arr[lookup[L, R]]);
        }
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
        int[] a = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
        int n = a.Length;
        Query[] q = { new Query(0, 4), new Query(4, 7),
                      new Query(7, 8) };
        int m = q.Length;
        RMQ(a, n, q, m);
    }
}
 
// This code is contributed by PrinciRaj1992


C++
// C++ program to do range minimum
// query in O(1) time with
// O(n Log n) extra space and
// O(n Log n) preprocessing time
#include 
using namespace std;
#define MAX 500
 
// lookup[i][j] is going to
// store index of minimum value in
// arr[i..j]. Ideally lookup
// table size should not be fixed
// and should be determined using
// n Log n. It is kept
// constant to keep code simple.
int lookup[MAX][MAX];
 
// Structure to represent a query range
struct Query {
    int L, R;
};
 
// Fills lookup array
// lookup[][] in bottom up manner.
void preprocess(int arr[], int n)
{
    // Initialize M for the
    // intervals with length 1
    for (int i = 0; i < n; i++)
        lookup[i][0] = i;
 
    // Compute values from smaller
    // to bigger intervals
    for (int j = 1; (1 << j) <= n; j++)
    {
        // Compute minimum value for
        // all intervals with size
        // 2^j
        for (int i = 0; (i + (1 << j) - 1) < n; i++)
        {
            // For arr[2][10], we
            // compare arr[lookup[0][3]]
            // and arr[lookup[3][3]]
            if (arr[lookup[i][j - 1]]
                < arr[lookup[i + (1 << (j - 1))][j - 1]])
                lookup[i][j] = lookup[i][j - 1];
            else
                lookup[i][j]
                    = lookup[i + (1 << (j - 1))][j - 1];
        }
    }
}
 
// Returns minimum of arr[L..R]
int query(int arr[], int L, int R)
{
    // For [2,10], j = 3
    int j = (int)log2(R - L + 1);
 
    // For [2,10], we compare arr[lookup[0][3]] and
    // arr[lookup[3][3]],
    if (arr[lookup[L][j]]
        <= arr[lookup[R - (1 << j) + 1][j]])
        return arr[lookup[L][j]];
 
    else
        return arr[lookup[R - (1 << j) + 1][j]];
}
 
// Prints minimum of given
// m query ranges in arr[0..n-1]
void RMQ(int arr[], int n, Query q[], int m)
{
    // Fills table lookup[n][Log n]
    preprocess(arr, n);
 
    // 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[i].L, R = q[i].R;
 
        // Print sum of current query range
        cout << "Minimum of [" << L << ", "
             << R << "] is "
             << query(arr, L, R) << endl;
    }
}
 
// Driver code
int main()
{
    int a[] = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
    int n = sizeof(a) / sizeof(a[0]);
    Query q[] = { { 0, 4 }, { 4, 7 }, { 7, 8 } };
    int m = sizeof(q) / sizeof(q[0]);
    RMQ(a, n, q, m);
    return 0;
}


Java
// Java program to do range minimum query
// in O(1) time with O(n Log n) extra space
// and O(n Log n) preprocessing time
import java.util.*;
 
class GFG {
 
    static int MAX = 500;
 
    // lookup[i][j] is going to store index
    // of minimum value in arr[i..j].
    // Ideally lookup table size should not be fixed
    // and should be determined using n Log n.
    // It is kept constant to keep code simple.
    static int[][] lookup = new int[MAX][MAX];
 
    // Structure to represent a query range
    static class Query {
        int L, R;
 
        public Query(int L, int R)
        {
            this.L = L;
            this.R = R;
        }
    };
 
    // Fills lookup array lookup[][]
    // in bottom up manner.
    static void preprocess(int arr[], int n)
    {
        // Initialize M for the intervals
        // with length 1
        for (int i = 0; i < n; i++)
            lookup[i][0] = i;
 
        // Compute values from smaller
        // to bigger intervals
        for (int j = 1; (1 << j) <= n; j++)
        {
            // Compute minimum value for
            // all intervals with size 2^j
            for (int i = 0;
                 (i + (1 << j) - 1) < n;
                 i++)
            {
                // For arr[2][10], we compare
                // arr[lookup[0][3]]
                // and arr[lookup[3][3]]
                if (arr[lookup[i][j - 1]]
                    < arr[lookup[i + (1 << (j - 1))]
                                [j - 1]])
                    lookup[i][j] = lookup[i][j - 1];
                else
                    lookup[i][j]
                        = lookup[i + (1 << (j - 1))][j - 1];
            }
        }
    }
 
    // Returns minimum of arr[L..R]
    static int query(int arr[], int L, int R)
    {
        // For [2,10], j = 3
        int j = (int)Math.log(R - L + 1);
 
        // For [2,10], we compare
        // arr[lookup[0][3]]
        // and arr[lookup[3][3]],
        if (arr[lookup[L][j]]
            <= arr[lookup[R - (1 << j) + 1][j]])
            return arr[lookup[L][j]];
 
        else
            return arr[lookup[R - (1 << j) + 1][j]];
    }
 
    // Prints minimum of given m
    // query ranges in arr[0..n-1]
    static void RMQ(int arr[], int n,
                    Query q[], int m)
    {
        // Fills table lookup[n][Log n]
        preprocess(arr, n);
 
        // 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[i].L, R = q[i].R;
 
            // Print sum of current query range
            System.out.println("Minimum of ["
                                
                               + L + ", " + R
                               + "] is "
                               + query(arr, L, R));
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int a[] = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
        int n = a.length;
        Query q[] = { new Query(0, 4), new Query(4, 7),
                      new Query(7, 8) };
        int m = q.length;
        RMQ(a, n, q, m);
    }
}
 
// This code is contributed by Rajput-Ji


Python3
# Python3 program to do range minimum query
# in O(1) time with O(n Log n) extra space
# and O(n Log n) preprocessing time
from math import log2
 
MAX = 500
 
# lookup[i][j] is going to store index of
# minimum value in arr[i..j].
# Ideally lookup table size should
# not be fixed and should be determined
# using n Log n. It is kept constant
# to keep code simple.
lookup = [[0 for i in range(500)]
          for j in range(500)]
 
# Structure to represent a query range
 
 
class Query:
    def __init__(self, l, r):
        self.L = l
        self.R = r
 
# Fills lookup array lookup[][]
# in bottom up manner.
 
 
def preprocess(arr: list, n: int):
    global lookup
 
    # Initialize M for the
    # intervals with length 1
    for i in range(n):
        lookup[i][0] = i
 
    # Compute values from
    # smaller to bigger intervals
    j = 1
    while (1 << j) <= n:
 
        # Compute minimum value for
        # all intervals with size 2^j
        i = 0
        while i + (1 << j) - 1 < n:
 
            # For arr[2][10], we compare
            # arr[lookup[0][3]] and
            # arr[lookup[3][3]]
            if (arr[lookup[i][j - 1]] <
                    arr[lookup[i + (1 << (j - 1))][j - 1]]):
                lookup[i][j] = lookup[i][j - 1]
            else:
                lookup[i][j] = lookup[i +
                                      (1 << (j - 1))][j - 1]
 
            i += 1
        j += 1
 
# Returns minimum of arr[L..R]
 
 
def query(arr: list, L: int, R: int) -> int:
    global lookup
 
    # For [2,10], j = 3
    j = int(log2(R - L + 1))
 
    # For [2,10], we compare
    # arr[lookup[0][3]] and
    # arr[lookup[3][3]],
    if (arr[lookup[L][j]] <=
            arr[lookup[R - (1 << j) + 1][j]]):
        return arr[lookup[L][j]]
    else:
        return arr[lookup[R - (1 << j) + 1][j]]
 
# Prints minimum of given
# m query ranges in arr[0..n-1]
 
 
def RMQ(arr: list, n: int, q: list, m: int):
 
    # Fills table lookup[n][Log n]
    preprocess(arr, n)
 
    # One by one compute sum of all queries
    for i in range(m):
 
        # Left and right boundaries
        # of current range
        L = q[i].L
        R = q[i].R
 
        # Print sum of current query range
        print("Minimum of [%d, %d] is %d" %
              (L, R, query(arr, L, R)))
 
 
# Driver Code
if __name__ == "__main__":
    a = [7, 2, 3, 0, 5, 10, 3, 12, 18]
    n = len(a)
    q = [Query(0, 4), Query(4, 7),
         Query(7, 8)]
    m = len(q)
 
    RMQ(a, n, q, m)
 
# This code is contributed by
# sanjeev2552


C#
// C# program to do range minimum query
// in O(1) time with O(n Log n) extra space
// and O(n Log n) preprocessing time
using System;
 
class GFG {
 
    static int MAX = 500;
 
    // lookup[i,j] is going to store index
    // of minimum value in arr[i..j].
    // Ideally lookup table size should not be fixed
    // and should be determined using n Log n.
    // It is kept constant to keep code simple.
    static int[, ] lookup = new int[MAX, MAX];
 
    // Structure to represent a query range
    public class Query {
        public int L, R;
 
        public Query(int L, int R)
        {
            this.L = L;
            this.R = R;
        }
    };
 
    // Fills lookup array lookup[,]
    // in bottom up manner.
    static void preprocess(int[] arr, int n)
    {
        // Initialize M for the intervals
        // with length 1
        for (int i = 0; i < n; i++)
            lookup[i, 0] = i;
 
        // Compute values from smaller
        // to bigger intervals
        for (int j = 1; (1 << j) <= n; j++)
        {
            // Compute minimum value for
            // all intervals with size 2^j
            for (int i = 0;
                 (i + (1 << j) - 1) < n;
                 i++)
            {
                // For arr[2,10], we compare
                // arr[lookup[0,3]] and arr[lookup[3,3]]
                if (arr[lookup[i, j - 1]]
                    < arr[lookup[i + (1 << (j - 1)),
                                 j - 1]])
                    lookup[i, j] = lookup[i, j - 1];
                else
                    lookup[i, j]
                        = lookup[i + (1 << (j - 1)), j - 1];
            }
        }
    }
 
    // Returns minimum of arr[L..R]
    static int query(int[] arr, int L, int R)
    {
        // For [2,10], j = 3
        int j = (int)Math.Log(R - L + 1);
 
        // For [2,10], we compare arr[lookup[0,3]]
        // and arr[lookup[3,3]],
        if (arr[lookup[L, j]]
            <= arr[lookup[R - (1 << j) + 1, j]])
            return arr[lookup[L, j]];
 
        else
            return arr[lookup[R - (1 << j) + 1, j]];
    }
 
    // Prints minimum of given m
    // query ranges in arr[0..n-1]
    static void RMQ(int[] arr,
                    int n, Query[] q, int m)
    {
        // Fills table lookup[n,Log n]
        preprocess(arr, n);
 
        // 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[i].L, R = q[i].R;
 
            // Print sum of current query range
            Console.WriteLine("Minimum of [" + L + ", " + R
                              + "] is " + query(arr, L, R));
        }
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
        int[] a = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
        int n = a.Length;
        Query[] q = { new Query(0, 4), new Query(4, 7),
                      new Query(7, 8) };
        int m = q.Length;
        RMQ(a, n, q, m);
    }
}
 
// This code is contributed by Princi Singh


输出:

Minimum of [0, 4] is 0
Minimum of [4, 7] is 3
Minimum of [7, 8] is 12





这种方法支持O(1)中的查询,但是预处理需要O(n 2 )时间。而且,此方法需要O(n 2 )额外空间,这对于大型输入阵列可能会变得很大。

方法2(平方根分解)
我们可以使用平方根分解来减少上述方法所需的空间。
预处理:
1)将范围[0,n-1]划分为√n的不同块。
2)计算每个大小为√n的块的最小值,并存储结果。
预处理需要O(√n*√n)= O(n)时间和O(√n)空间。

rmq3

询问:
1)要查询范围[L,R],我们要取该范围内所有块的最小值。对于可能与给定范围部分重叠的左,右角块,我们对其进行线性扫描以找到最小值。
查询的时间复杂度为O(√n) 。请注意,我们至少有一个直接可访问的中间块,并且最多可以有O(√n)个中间块。我们最多可能需要扫描两个角块,因此我们可能必须扫描角块的2 * O(√n)个元素。因此,总时间复杂度为O(√n)
请参阅Sqrt(或平方根)分解技术|设置1(简介)以获取详细信息。

方法3(稀疏表算法)
上面的解决方案只需要O(√n)空间,但是要花O(√n)时间查询。稀疏表方法支持查询时间O(1)和额外空间O(n Log n)
这个想法是预先计算所有大小为2 j的子数组的最小值,其中j从0到Log n变化。像方法1一样,我们创建一个查找表。在这里,lookup [i] [j]包含从i开始且范围为2 j的最小范围。例如,lookup [0] [3]包含范围为[0,7]的最小值(从0开始,大小为2 3 )。

预处理:
如何填写此查询表?这个想法很简单,使用以前计算的值以自下而上的方式填充。
例如,要找到范围[0,7]的最小值,我们可以使用以下两个值中的最小值。
a)范围[0,3]的最小值
b)最小范围[4,7]
根据上面的示例,下面是公式,

// If arr[lookup[0][2]] <=  arr[lookup[4][2]], 
// then lookup[0][3] = lookup[0][2]
If arr[lookup[i][j-1]] <= arr[lookup[i+2j-1][j-1]]
   lookup[i][j] = lookup[i][j-1]

// If arr[lookup[0][2]] >  arr[lookup[4][2]], 
// then lookup[0][3] = lookup[4][2]
Else 
   lookup[i][j] = lookup[i+2j-1][j-1] 

rmqsparsetable

询问:
对于任意范围[l,R],我们需要使用2的幂的范围。想法是使用2的最接近的幂。我们总是需要最多进行一次比较(比较两个范围的最小值,是2的幂。一个范围以L开头,以“ L +最近的2的幂”结尾。另一个范围以R结束,并以“ R – 2的最接近功率+1”开头。例如,如果给定范围是(2,10),我们比较两个范围(2,9)和(3,10)中的最小值。
根据上面的示例,下面是公式,

// For (2,10), j = floor(Log2(10-2+1)) = 3
j = floor(Log(R-L+1))

// If arr[lookup[0][3]] <=  arr[lookup[3][3]], 
// then RMQ(2,10) = lookup[0][3]
If arr[lookup[L][j]] <= arr[lookup[R-(int)pow(2,j)+1][j]]
   RMQ(L, R) = lookup[L][j]

// If arr[lookup[0][3]] >  arr[lookup[3][3]], 
// then RMQ(2,10) = lookup[3][3]
Else 
   RMQ(L, R) = lookup[R-(int)pow(2,j)+1][j]

由于我们只进行一次比较,因此查询的时间复杂度为O(1)。

以下是上述想法的实现。

C++

// C++ program to do range minimum
// query in O(1) time with
// O(n Log n) extra space and
// O(n Log n) preprocessing time
#include 
using namespace std;
#define MAX 500
 
// lookup[i][j] is going to
// store index of minimum value in
// arr[i..j]. Ideally lookup
// table size should not be fixed
// and should be determined using
// n Log n. It is kept
// constant to keep code simple.
int lookup[MAX][MAX];
 
// Structure to represent a query range
struct Query {
    int L, R;
};
 
// Fills lookup array
// lookup[][] in bottom up manner.
void preprocess(int arr[], int n)
{
    // Initialize M for the
    // intervals with length 1
    for (int i = 0; i < n; i++)
        lookup[i][0] = i;
 
    // Compute values from smaller
    // to bigger intervals
    for (int j = 1; (1 << j) <= n; j++)
    {
        // Compute minimum value for
        // all intervals with size
        // 2^j
        for (int i = 0; (i + (1 << j) - 1) < n; i++)
        {
            // For arr[2][10], we
            // compare arr[lookup[0][3]]
            // and arr[lookup[3][3]]
            if (arr[lookup[i][j - 1]]
                < arr[lookup[i + (1 << (j - 1))][j - 1]])
                lookup[i][j] = lookup[i][j - 1];
            else
                lookup[i][j]
                    = lookup[i + (1 << (j - 1))][j - 1];
        }
    }
}
 
// Returns minimum of arr[L..R]
int query(int arr[], int L, int R)
{
    // For [2,10], j = 3
    int j = (int)log2(R - L + 1);
 
    // For [2,10], we compare arr[lookup[0][3]] and
    // arr[lookup[3][3]],
    if (arr[lookup[L][j]]
        <= arr[lookup[R - (1 << j) + 1][j]])
        return arr[lookup[L][j]];
 
    else
        return arr[lookup[R - (1 << j) + 1][j]];
}
 
// Prints minimum of given
// m query ranges in arr[0..n-1]
void RMQ(int arr[], int n, Query q[], int m)
{
    // Fills table lookup[n][Log n]
    preprocess(arr, n);
 
    // 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[i].L, R = q[i].R;
 
        // Print sum of current query range
        cout << "Minimum of [" << L << ", "
             << R << "] is "
             << query(arr, L, R) << endl;
    }
}
 
// Driver code
int main()
{
    int a[] = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
    int n = sizeof(a) / sizeof(a[0]);
    Query q[] = { { 0, 4 }, { 4, 7 }, { 7, 8 } };
    int m = sizeof(q) / sizeof(q[0]);
    RMQ(a, n, q, m);
    return 0;
}

Java

// Java program to do range minimum query
// in O(1) time with O(n Log n) extra space
// and O(n Log n) preprocessing time
import java.util.*;
 
class GFG {
 
    static int MAX = 500;
 
    // lookup[i][j] is going to store index
    // of minimum value in arr[i..j].
    // Ideally lookup table size should not be fixed
    // and should be determined using n Log n.
    // It is kept constant to keep code simple.
    static int[][] lookup = new int[MAX][MAX];
 
    // Structure to represent a query range
    static class Query {
        int L, R;
 
        public Query(int L, int R)
        {
            this.L = L;
            this.R = R;
        }
    };
 
    // Fills lookup array lookup[][]
    // in bottom up manner.
    static void preprocess(int arr[], int n)
    {
        // Initialize M for the intervals
        // with length 1
        for (int i = 0; i < n; i++)
            lookup[i][0] = i;
 
        // Compute values from smaller
        // to bigger intervals
        for (int j = 1; (1 << j) <= n; j++)
        {
            // Compute minimum value for
            // all intervals with size 2^j
            for (int i = 0;
                 (i + (1 << j) - 1) < n;
                 i++)
            {
                // For arr[2][10], we compare
                // arr[lookup[0][3]]
                // and arr[lookup[3][3]]
                if (arr[lookup[i][j - 1]]
                    < arr[lookup[i + (1 << (j - 1))]
                                [j - 1]])
                    lookup[i][j] = lookup[i][j - 1];
                else
                    lookup[i][j]
                        = lookup[i + (1 << (j - 1))][j - 1];
            }
        }
    }
 
    // Returns minimum of arr[L..R]
    static int query(int arr[], int L, int R)
    {
        // For [2,10], j = 3
        int j = (int)Math.log(R - L + 1);
 
        // For [2,10], we compare
        // arr[lookup[0][3]]
        // and arr[lookup[3][3]],
        if (arr[lookup[L][j]]
            <= arr[lookup[R - (1 << j) + 1][j]])
            return arr[lookup[L][j]];
 
        else
            return arr[lookup[R - (1 << j) + 1][j]];
    }
 
    // Prints minimum of given m
    // query ranges in arr[0..n-1]
    static void RMQ(int arr[], int n,
                    Query q[], int m)
    {
        // Fills table lookup[n][Log n]
        preprocess(arr, n);
 
        // 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[i].L, R = q[i].R;
 
            // Print sum of current query range
            System.out.println("Minimum of ["
                                
                               + L + ", " + R
                               + "] is "
                               + query(arr, L, R));
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int a[] = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
        int n = a.length;
        Query q[] = { new Query(0, 4), new Query(4, 7),
                      new Query(7, 8) };
        int m = q.length;
        RMQ(a, n, q, m);
    }
}
 
// This code is contributed by Rajput-Ji

Python3

# Python3 program to do range minimum query
# in O(1) time with O(n Log n) extra space
# and O(n Log n) preprocessing time
from math import log2
 
MAX = 500
 
# lookup[i][j] is going to store index of
# minimum value in arr[i..j].
# Ideally lookup table size should
# not be fixed and should be determined
# using n Log n. It is kept constant
# to keep code simple.
lookup = [[0 for i in range(500)]
          for j in range(500)]
 
# Structure to represent a query range
 
 
class Query:
    def __init__(self, l, r):
        self.L = l
        self.R = r
 
# Fills lookup array lookup[][]
# in bottom up manner.
 
 
def preprocess(arr: list, n: int):
    global lookup
 
    # Initialize M for the
    # intervals with length 1
    for i in range(n):
        lookup[i][0] = i
 
    # Compute values from
    # smaller to bigger intervals
    j = 1
    while (1 << j) <= n:
 
        # Compute minimum value for
        # all intervals with size 2^j
        i = 0
        while i + (1 << j) - 1 < n:
 
            # For arr[2][10], we compare
            # arr[lookup[0][3]] and
            # arr[lookup[3][3]]
            if (arr[lookup[i][j - 1]] <
                    arr[lookup[i + (1 << (j - 1))][j - 1]]):
                lookup[i][j] = lookup[i][j - 1]
            else:
                lookup[i][j] = lookup[i +
                                      (1 << (j - 1))][j - 1]
 
            i += 1
        j += 1
 
# Returns minimum of arr[L..R]
 
 
def query(arr: list, L: int, R: int) -> int:
    global lookup
 
    # For [2,10], j = 3
    j = int(log2(R - L + 1))
 
    # For [2,10], we compare
    # arr[lookup[0][3]] and
    # arr[lookup[3][3]],
    if (arr[lookup[L][j]] <=
            arr[lookup[R - (1 << j) + 1][j]]):
        return arr[lookup[L][j]]
    else:
        return arr[lookup[R - (1 << j) + 1][j]]
 
# Prints minimum of given
# m query ranges in arr[0..n-1]
 
 
def RMQ(arr: list, n: int, q: list, m: int):
 
    # Fills table lookup[n][Log n]
    preprocess(arr, n)
 
    # One by one compute sum of all queries
    for i in range(m):
 
        # Left and right boundaries
        # of current range
        L = q[i].L
        R = q[i].R
 
        # Print sum of current query range
        print("Minimum of [%d, %d] is %d" %
              (L, R, query(arr, L, R)))
 
 
# Driver Code
if __name__ == "__main__":
    a = [7, 2, 3, 0, 5, 10, 3, 12, 18]
    n = len(a)
    q = [Query(0, 4), Query(4, 7),
         Query(7, 8)]
    m = len(q)
 
    RMQ(a, n, q, m)
 
# This code is contributed by
# sanjeev2552

C#

// C# program to do range minimum query
// in O(1) time with O(n Log n) extra space
// and O(n Log n) preprocessing time
using System;
 
class GFG {
 
    static int MAX = 500;
 
    // lookup[i,j] is going to store index
    // of minimum value in arr[i..j].
    // Ideally lookup table size should not be fixed
    // and should be determined using n Log n.
    // It is kept constant to keep code simple.
    static int[, ] lookup = new int[MAX, MAX];
 
    // Structure to represent a query range
    public class Query {
        public int L, R;
 
        public Query(int L, int R)
        {
            this.L = L;
            this.R = R;
        }
    };
 
    // Fills lookup array lookup[,]
    // in bottom up manner.
    static void preprocess(int[] arr, int n)
    {
        // Initialize M for the intervals
        // with length 1
        for (int i = 0; i < n; i++)
            lookup[i, 0] = i;
 
        // Compute values from smaller
        // to bigger intervals
        for (int j = 1; (1 << j) <= n; j++)
        {
            // Compute minimum value for
            // all intervals with size 2^j
            for (int i = 0;
                 (i + (1 << j) - 1) < n;
                 i++)
            {
                // For arr[2,10], we compare
                // arr[lookup[0,3]] and arr[lookup[3,3]]
                if (arr[lookup[i, j - 1]]
                    < arr[lookup[i + (1 << (j - 1)),
                                 j - 1]])
                    lookup[i, j] = lookup[i, j - 1];
                else
                    lookup[i, j]
                        = lookup[i + (1 << (j - 1)), j - 1];
            }
        }
    }
 
    // Returns minimum of arr[L..R]
    static int query(int[] arr, int L, int R)
    {
        // For [2,10], j = 3
        int j = (int)Math.Log(R - L + 1);
 
        // For [2,10], we compare arr[lookup[0,3]]
        // and arr[lookup[3,3]],
        if (arr[lookup[L, j]]
            <= arr[lookup[R - (1 << j) + 1, j]])
            return arr[lookup[L, j]];
 
        else
            return arr[lookup[R - (1 << j) + 1, j]];
    }
 
    // Prints minimum of given m
    // query ranges in arr[0..n-1]
    static void RMQ(int[] arr,
                    int n, Query[] q, int m)
    {
        // Fills table lookup[n,Log n]
        preprocess(arr, n);
 
        // 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[i].L, R = q[i].R;
 
            // Print sum of current query range
            Console.WriteLine("Minimum of [" + L + ", " + R
                              + "] is " + query(arr, L, R));
        }
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
        int[] a = { 7, 2, 3, 0, 5, 10, 3, 12, 18 };
        int n = a.Length;
        Query[] q = { new Query(0, 4), new Query(4, 7),
                      new Query(7, 8) };
        int m = q.Length;
        RMQ(a, n, q, m);
    }
}
 
// This code is contributed by Princi Singh
输出
Minimum of [0, 4] is 0
Minimum of [4, 7] is 3
Minimum of [7, 8] is 12