倍增和 ST 表
倍增,顾名思义就是成倍增长。可以在
倍增主要运用于 RMQ 问题或 LCA 问题。
思想
举个例子,假设现在给定了一个长度为
暴力找?
具体实现
令 mx[i][j]
表示 mx[i][0] = a[i]
,当 j
为正数时 mx[i][j] = max(mx[i][j - 1], mx[max(0, i - (1 << (j - 1)))][j - 1])
。
询问处理
对于一段区间 mx[r][i]
会产生共享,统计进去,再右移
时间复杂度:
除了维护区间 RMQ,还可以
首先预处理出每个节点的 fa[i][j]
表示 j
为正数时,fa[i][j] = fa[fa[i][j - 1]][j - 1]
。
当要求 h[i]
表示节点 h[x] <= h[y]
,那么就先让 h[y] - h[x]
级祖先处,如果此时
否则,按位(fa[x][i] != fa[y][i]
,那么 x = fa[x][i], y = fa[y][i]
,最后返回 fa[x][0]
即可。
ST 表是用于解决可重复贡献问题的数据结构(例如解决区间 RMQ 或区间 gcd 等问题),基于倍增思想。
还是用上面的例子,求一段区间的最大值。倍增可以
思想
首先和倍增一样预处理。
由于 RMQ 问题是可重复共献问题(即只要处理的区间在询问区间范围内且包含了范围内的所有可贡献元素,即使重复计算也不影响答案),所以可以考虑将其拆分成两个区间处理,只要这两个区间的并集为
处理
首先预处理出
那么就好办了,对于一个区间 max(mx[r][Log[r - l + 1]], mx[l + (1 << Log[r - l + 1]) - 1][Log[r - l + 1]])
。
询问
P3865 【模板】ST 表
#include <iostream> using namespace std; const int N = 1e5 + 10; int n, m, mx[N][20], l, r, Log[N]; int main () { ios::sync_with_stdio(0), cin.tie(0); cin >> n >> m, Log[0] = -1; for (int i = 1; i <= n; i++) { cin >> mx[i][0], Log[i] = Log[i / 2] + 1; } for (int i = 1; i <= 16; i++) { for (int j = (1 << i); j <= n; j++) { mx[j][i] = max(mx[j][i - 1], mx[j - (1 << (i - 1))][i - 1]); } } for (int i = 1; i <= m; i++) { cin >> l >> r; cout << max(mx[r][Log[r - l + 1]], mx[l + (1 << Log[r - l + 1]) - 1][Log[r - l + 1]]) << '\n'; } return 0; }
本文作者:wnsyou
本文链接:https://www.cnblogs.com/wnsyou-blog/p/binary_lifting.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步