ST算法介绍

  1. ST 表是用于解决 可重复贡献问题 的数据结构

image.png

  1. ST算法,能在 O(nlogn)时间的预处理后,以O(1)的时间复杂度在线回答
  2. "数列A中下标在l~r之间的数的最大值是多少"
  3. 这样的区间最值问题

image.png

  1. // dp[i][j]表示数列在[i, i + 2 ^ j - 1]里的最大值
  2. // 初始状态是 dp[i][0] = a[i]
  3. // 递推公式 dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1])
  4. void ST_prework(){
  5. for (int i = 1; i <= n; i++) dp[i][0] = a[i];
  6. int Log = (int)(log(1.0 * n) / log(2.0)) + 1;
  7. for (int j = 1; j < Log; j++)
  8. for (int i = 1; i <= n - (1 << j) + 1; i++)
  9. dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
  10. }

image.png

  1. 询问时,
  2. 先计算出使得2^k 小于区间长度,且最大
  3. 那么,就可以用 "从l开始的2^k个数" "以r结尾的2^k个数",这两段覆盖整个区间[l, r]
  4. 即使有重叠也没关系
  5. int ST_query(int l, int r){
  6. int k = (int)(log(1.0 * (r - l + 1)) / log(2.0));
  7. return max(dp[l][k], dp[r - (1 << k) + 1][k]);
  8. }

关于log的预处理

  1. 1、使用cmathlog函数,执行效率很高,影响不大。需要注意的是,参数和返回值都是double
  2. double log (double x);
  3. 2、手动预处理
  4. int Log[N]; // 预处理log
  5. Log[1] = 0;
  6. for (int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;

ST算法特点

  1. ST
  2. 能较好的维护“可重复贡献”的区间信息(同时也应满足结合律),
  3. 时间复杂度较低,
  4. 代码量相对其他算法很小。
  5. 但是,ST 表能维护的信息非常有限,不能较好地扩展,并且不支持修改操作

例题

POJ - 3368 Frequent values