倍增
声明
该系列仅对套路总结出模板,并不是知识讲解
步骤
-
定义
a存放数组元素,f[i][j]存放从i开始长为1<<j的区间的最值,所以j的大小应该是log2(n)
int a[10001], f[10001][30]; int n, m;//数组大小、查询次数 -
初始化
将所有长为1的区间最值初始化为a[i](只有一个数最值当然是他自己)
for(int i = 1; i <= n; i++) f[i][0] = a[i];//f[i][0]指从i开始长度为1的区间 -
预处理
计算所有f的值,直接dp
跟区间dp套路类似,从小到大枚举区间长度和左端点
i代表区间长度,j代表左端点
j + (1 << p) - 1 <= n就是指左端点加区间长度-1(即右端点的位置)要小于等于n
int p = log2(n);//区间长度最大为(1 << p)for(int i = 1; i <= p; i++) for(int j = 1; j + (1 << p) - 1 <= n; j++) f[j][i] = min/max(f[j][i - 1], f[j + (1 << i)][i - 1]); -
查询
记住变量尽量在循环外定义,这部分通常会根据题意调整,但始终牢记查询的方式即可
即:
p = log2(r - l + 1);//p之前定义过 ans = min/max(f[l][p], f[r - (1 << p) + 1][p]);给他套个循环的壳子
int l, r, ans;//查询区间 while(m--){ scanf("%d%d", &l, &r); p = log2(r - l + 1);//p之前定义过 ans = min/max(f[l][p], f[r - (1 << p) + 1][p]); printf("%d\n", ans); }整体代码
还是很清晰的
#include <bits/stdc++.h> using namespace std; int a[10001], f[10001][30]; int n, m; int main(){ for(int i = 1; i <= n; i++) scanf("%d", a[i]); for(int i = 1; i <= n; i++) f[i][0] = a[i]; int p = log2(n); for(int i = 1; i <= p; i++) for(int j = 1; j + (1 << p) - 1 <= n; j++) f[j][i] = min/max(f[j][i - 1], f[j + (1 << i)][i - 1]); int l, r, ans; while(m--){ scanf("%d%d", &l, &r); p = log2(r - l + 1); ans = min/max(f[l][p], f[r - (1 << p) + 1][p]); printf("%d\n", ans); } }
本文介绍了一种高效处理区间最值查询的方法——倍增算法。通过预处理数组,可以在O(log N)时间内完成任意区间内的最小值或最大值查询。文章详细阐述了算法原理、实现步骤及代码示例。
489

被折叠的 条评论
为什么被折叠?



