Official

E - 山の高さ調査 / Mountain Height Survey Editorial by admin

Claude 4.5 Opus

Overview

This is a problem about efficiently processing multiple queries for “Range Maximum Query (RMQ)” - finding the maximum elevation within a specified interval of a mountain range.

Analysis

Naive Approach and Its Problems

The most intuitive method is to simply loop through the specified interval \([L, R]\) for each query to find the maximum value.

for i in range(L-1, R):
    ans = max(ans, A[i])

However, this method takes \(O(N)\) per query, resulting in \(O(NQ)\) overall. When both \(N\) and \(Q\) are at most \(10^5\), this requires \(10^{10}\) operations, which will not finish within the time limit (TLE).

Solution Strategy

When there are many queries, the approach of performing preprocessing to handle queries efficiently is effective. For range maximum queries, a data structure called “Sparse Table” is suitable.

Algorithm

What is a Sparse Table?

Sparse Table is a technique that precomputes information for intervals whose lengths are powers of 2.

  • sparse_table[k][i] = maximum value in the interval of length \(2^k\) starting at position \(i\)
    • In other words, \(\max(A[i], A[i+1], \ldots, A[i+2^k-1])\)

Construction Method

  1. Base case (k=0): An interval of length \(2^0 = 1\) is just the element itself

    • sparse_table[0][i] = A[i]
  2. Recurrence relation (k≥1): Divide an interval of length \(2^k\) into two intervals of length \(2^{k-1}\)

    • sparse_table[k][i] = max(sparse_table[k-1][i], sparse_table[k-1][i + 2^(k-1)])

Query Response

To find the maximum value in interval \([l, r]\) (0-indexed):

  1. For the interval length \(len = r - l + 1\), find the maximum \(k\) such that \(2^k \leq len\)
  2. Cover the interval with two overlapping intervals:
    • From the left: \([l, l + 2^k - 1]\)
    • From the right: \([r - 2^k + 1, r]\)
  3. The larger of the maximum values from both intervals is the answer

Concrete example: For interval \([1, 5]\) (length 5) - \(k = 2\) (\(2^2 = 4 \leq 5\)) - Compare the maximum values of intervals \([1, 4]\) and \([2, 5]\)

![Sparse Table visualization](Even with overlap, the correct result is obtained since we’re taking max)

Complexity

  • Preprocessing (Sparse Table construction)

    • Time complexity: \(O(N \log N)\)
    • Space complexity: \(O(N \log N)\)
  • Each query response

    • Time complexity: \(O(1)\)
  • Overall

    • Time complexity: \(O(N \log N + Q)\)
    • Space complexity: \(O(N \log N)\)

Implementation Notes

  1. Converting from 1-indexed to 0-indexed: Since the problem uses mountain numbers starting from 1, convert to L-1, R-1 when accessing the array

  2. Precomputing the log table: Computing \(\log_2\) for each query is slow, so create a table in advance

    log_table[i] = log_table[i // 2] + 1
    
  3. Optimizing output: Reduce I/O overhead by accumulating results in a list and outputting them all at once at the end

  4. Utilizing the property that max tolerates duplicate calculations: Sparse Table is applicable to operations where “computing the same element multiple times doesn’t change the result,” such as min/max/gcd

    Source Code

import sys
from math import log2, ceil

def main():
    input = sys.stdin.readline
    
    N, Q = map(int, input().split())
    A = list(map(int, input().split()))
    
    # Sparse Table for Range Maximum Query
    # sparse_table[k][i] = max of A[i:i+2^k]
    
    if N == 0:
        for _ in range(Q):
            print(0)
        return
    
    LOG = max(1, ceil(log2(N + 1)))
    
    # Initialize sparse table
    sparse_table = [[0] * N for _ in range(LOG + 1)]
    
    # Base case: intervals of length 1
    for i in range(N):
        sparse_table[0][i] = A[i]
    
    # Build sparse table
    for k in range(1, LOG + 1):
        length = 1 << k
        half = 1 << (k - 1)
        for i in range(N - length + 1):
            sparse_table[k][i] = max(sparse_table[k-1][i], sparse_table[k-1][i + half])
    
    # Precompute log2 values
    log_table = [0] * (N + 1)
    for i in range(2, N + 1):
        log_table[i] = log_table[i // 2] + 1
    
    # Answer queries
    results = []
    for _ in range(Q):
        L, R = map(int, input().split())
        # Convert to 0-indexed
        l = L - 1
        r = R - 1
        length = r - l + 1
        k = log_table[length]
        # max of [l, l + 2^k) and [r - 2^k + 1, r + 1)
        ans = max(sparse_table[k][l], sparse_table[k][r - (1 << k) + 1])
        results.append(ans)
    
    print('\n'.join(map(str, results)))

if __name__ == "__main__":
    main()

This editorial was generated by claude4.5opus.

posted:
last update: