Loading

ST 表

ST 表

ST 表是用于解决大部分静态 RMQ 问题的数据结构。

引入

给定 \(n\) 个数,\(m\) 次询问,每次回答 \([l, r]\) 中的最大值。

首先,我们可以想到一个暴力的做法:每次枚举 \(l \sim r\) 中的所有数字,求出最大值。

但是,当 \(n\) 足够大时,是会超时的。

所以就需要 ST 表了。

ST 表

ST 表基于倍增思想,\(O(n \log n)\) 预处理,\(O(1)\) 询问,但是不支持修改操作,线段树和树状数组可以修改元素。

我们先看前一部分,

预处理

我们定义 \(f_{i, j}\) 表示 \([i, i + 2 ^ j - 1]\) 的最大值,就有递推式:\(f_{i, j} = max(f_{i, j - 1}, f_{i + 2 ^ {j - 1}}, j - 1)\)

void P() {
  for (int j = 1; j < 20; j++) {
    for (int i = 1; i + (1 << j) - 1 <= n; i++) {
      f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    }
  }
}

询问

我们可以发现,如果我们要求 \([l, r]\) 的最大值,其实就算所有合并的区间之间有重叠也没关系,也就是说,我们只需要求 \(max(f_{l, k}, f_{r - 2 ^ k + 1, k}) \ (2 ^ k \le r - l + 1)\) 即可,所以,我们需要预处理出所有 \(i \ (1 \le i \le n)\)\(\log\)

void P() {
  for (int j = 1; j < L; j++) {
    for (int i = 1; i + (1 << j) - 1 <= n; i++) {
      f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    }
  }

  log_2[1] = 0;
  for (int i = 2; i <= n; i++) {
    log_2[i] = log_2[i / 2] + 1;
  }
}

int Solve() {
  int p = log_2[r - l + 1];
  return max(f[l][p], f[r - (1 << p) + 1][p]);
}
posted @ 2025-05-04 10:18  Yan719  阅读(18)  评论(0)    收藏  举报