想学习一下LCA倍增,先 水一个黄题 学一下ST表ios
这是一个运用倍增思想,经过动态规划来计算区间最值的算法算法
求出区间最值学习
回答询问spa
求出区间最值:code
用f[i][j]
来存储从第 j 个点开始,向后 2 ^ i - 1 个点中的最值(包括自己)ip
利用二分法的思想,将区间 [ j,j +(2 ^ i)- 1 ] 平均(大概)分红两半get
能够算出,区间 [ j,j +(2 ^ i)- 1 ] 的长度为 2 ^ istring
因此一半的长度为 2 ^ i - 1it
那么分红的两个区间就为 [ j,j +(2 ^(i - 1)- 1 ] 和 [ j +(2 ^ i - 1 ),j +(2 ^ i)- 1 ] 。io
毫无疑问,
f[i][j] = max(f[i - 1][j],f[i - 1][j +(1 << i - 1)])
这样递推式就出来了
如今来想一下:
f[0][j]
就是从 j 开始向后数第 2 ^ 0 - 1 个点的最值,区间为 [ j,j ]
不用考虑,f[0][j]
就是第 j 个数自己
好了,如今边界也得出来了,能够开始 dp 了
上代码:
void prew() { F1(i, 1, n) f[0][i] = a[i]; // 给边界赋值,a[i] 存的是数列的第 i 个数 int kf = log2(n); // 得出数列最多能够向后跳几个 2 的幂,n 为数列长度 F1(i, 1, kf) { // 枚举区间的长度 2 ^ i for (int j = 1; j + (1 << i) - 1 <= n; j++) // 枚举起点 f[i][j] = max(f[i - 1][j], f[i - 1][j + (1 << i - 1)]); // 递推式 } }
回答询问:
因为 log2 运算可能会出现实数,而咱们又用整数类型来存储,因此可能会出现两个区间不能彻底覆盖整个区间的状况,得出的 f[i][j]
不够精准
最简单的方法就是用两个区间覆盖
反正又没要求两个区间不能重叠~~
能够选用f[k][l]
和f[k][r-(1<<k)+1]
来覆盖f[l][r]
因此f[l][r] = max(f[k][l],f[k][r -(1 << k)+ 1])
(k 为区间 [l,r] 的长度的 log2)
再上代码:
int ask(int l, int r) { int k = log2(r - l + 1); // 求出区间最大的 log2 值 return max(f[k][l], f[k][r - (1 << k) + 1]); // 返回区间 [l,r] 的最大值 }
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <cmath> #include <algorithm> // 妈妈不再怕个人头文件不够使啦~~ #define MAXN 100100 #define INF 0x3f3f3f3f #define LL long long #define F1(i, a, b) for (LL i = a; i <= b; ++i) // 懒人必备神器 #define F2(i, a, b) for (LL i = a; i >= b; --i) using namespace std; int f[31][MAXN], a[MAXN]; //f[i][j]表示从 j 日后 2 ^ i - 1 个数中的最大值 int n, m; inline int read() { // 快读 int sto = 0, fg = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') fg = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { sto = (sto << 1) + (sto << 3) + (ch ^ 48); ch = getchar(); } return sto * fg; } void prew() { // 预处理 dp F1(i, 1, n) f[0][i] = a[i]; int kf = log2(n); F1(i, 1, kf) { for (int j = 1; j + (1 << i) - 1 <= n; j++) f[i][j] = max(f[i - 1][j], f[i - 1][j + (1 << i - 1)]); } } int ask(int l, int r) { // 回答询问 int k = log2(r - l + 1); return max(f[k][l], f[k][r - (1 << k) + 1]); } int main() { int l, r, ans; n = read(); m = read(); F1(i, 1, n) a[i] = read(); prew(); F1(i, 1, m) { l = read(); r = read(); ans = ask(l, r); printf("%d\n", ans); } return 0; }
模板题:
洛谷P3865