# CSES - Static Range Minimum Queries ```c++ #include<bits/stdc++.h> #define int long long using namespace std; const int mxn = 2e5; struct sprase_table{ int n; vector<vector<long long>> sp; sprase_table(vector<int> &x) : n(x.size()){ sp.resize(20, vector<int>(n)); for(int i = 0; i<n; i++){ sp[0][i] = x[i]; } for(int i = 1; i<20; i++){ for(int j = 0; j + (1 << i) -1 < n; j++){ sp[i][j] = min(sp[i-1][j], sp[i-1][j+(1 << (i)-1)]); } } } int ask(int l, int r){ int k = __lg(r - l); return min(sp[k][l], sp[k][r - (1 << k)]); } }; signed main(){ ios::sync_with_stdio(false); cin.tie(0); int n,q; cin >> n>> q; vector<int> x(n+1); for(int i =0; i<n; i++){ cin >> x[i]; } sprase_table sp(x); for(int i = 0; i<q; i++){ int a,b; cin >> a >> b; cout <<sp.ask(a-1,b) << "\n"; } return 0; } ``` sp[i][j] 代表什麼? 從 j 開始、長度 2^i 的區間最小值 --- ### 特性 1:我們預先算好所有 “長度為 2 的冪次方” 的區間最小值 例如陣列: [a0, a1, a2, a3, a4, a5, a6, a7] 我們會算: 長度 範例區間 Meaning * 2^0 = 1 [i] 單點最小值,就是原陣列 * 2^1 = 2 [i, i+2) 兩個一組的最小值 * 2^2 = 4 [i, i+4) 四個一組的最小值 * 2^3 = 8 [i, i+8) 八個一組的最小值 所有這些都在建構階段算好了。 ### 特性 2:任意區間都能被「兩段」相同長度的 2^k 區間覆蓋 ### 假設查詢 [l, r) 區間長度 = len = r - l 找出最大 k,使得: 2^k ≤ len 然後把查詢區間切成: **1. [l, l + 2^k) 2. [r - 2^k, r)** --- DiegoLin --------- 2025/10/24