定义

ST 表(Sparse Table)是一种用于静态区间查询的数据结构,支持 O(1) 时间查询,常用于区间最值查询等满足结合律的操作。构建复杂度为 O(n log n)不支持修改

原理

ST 表利用区间长度的二的幂来拆分任意区间,并预处理所有以2^j为长度的区间操作。
以最小值为例:
st[i][j]表示从a[i]开始,长度为2^j的区间的最小值。

  • st[2][0] = a[2]
  • st[2][1] = min(a[2], a[3])
  • st[2][2] = min(a[2], a[3], a[4], a[5])

建表

void build(const int n)  
{  
    for (int i = 1; i <= n; ++i)  
       st[i][0] = a[i]; // 区间长度为 1 时为 a[i]    
       for (int j = 1; 1 << j <= n; ++j) // 区间长度 = 2^j       
	       for (int i = 1; i + (1 << j) - 1 <= n; ++i) // 区间的起始位置 = i          
		       st[i][j] = min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);  
		    // st[i][j] = min(st[i][j - 1], st[i + 区间长度 / 2][j - 1])}
}

查询

int query(const int left, const int right)  
{  
    const int j = log2(right - left + 1); // 区间长度 = 2^j    
    return min(st[left][j], st[right - (1 << j) + 1][j]);  
}

模版

template <typename T, typename F>  
struct SparseTable  
{  
    T table[MAX_N][__lg(MAX_N) + 1];  
    F operation;  
  
    SparseTable(const T* a, F function) : operation(function)  
    {  
       for (int i = 1; i <= n; ++i)  
          table[i][0] = a[i];  
       for (int j = 1; (1 << j) <= n; ++j)  
          for (int i = 1; i + (1 << j) - 1 <= n; ++i)  
             table[i][j] = operation(table[i][j - 1], table[i + (1 << j - 1)][j - 1]);  
    }  
  
    T Query(const int left, const int right)  
    {  
       int j = __lg(right - left + 1);  
       return operation(table[left][j], table[right - (1 << j) + 1][j]);  
    }  
};

例:

vector<int> a(n + 1);
SparseTable min_st(a, [](const int x, const int y)  
{  
    return min(x, y);  
});
int min_value = min_st.query(1, n); //查询[1, n]的最小值