ST算法

 洛谷 3865

题目背景

这是一道ST表经典题——静态区间最大值

请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1)O(1)

题目描述

给定一个长度为 NN 的数列,和 MM 次询问,求出每一次询问的区间内数字的最大值。

输入输出格式

输入格式:

第一行包含两个整数 N, MN,M ,分别表示数列的长度和询问的个数。

第二行包含 NN 个整数(记为 a_iai​),依次表示数列的第 ii 项。

接下来 MM行,每行包含两个整数 l_i, r_ili​,ri​,表示查询的区间为 [ l_i, r_i][li​,ri​]

输出格式:

输出包含 MM行,每行一个整数,依次表示每一次询问的结果。

输入输出样例

输入样例#1: 复制

8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8

输出样例#1: 复制

9
9
7
7
9
8
7
9

说明

对于30%的数据,满足: 1 leq N, M leq 101≤N,M≤10

对于70%的数据,满足: 1 leq N, M leq {10}^51≤N,M≤105

对于100%的数据,满足: 1 leq N leq {10}^5, 1 leq M leq {10}^6, a_i in [0, {10}^9], 1 leq l_i leq r_i leq N1≤N≤105,1≤M≤106,ai​∈[0,109],1≤li​≤ri​≤N

题解

这道题目是一道st表的题目,洛谷里面已经有很详尽的解释了,但我还是要解释一波。

f[i][j] 的意思是,以第i个为起始的元素,然后到它后面第2^j-1个元素为止,这里面的最大值。

比如 f[1][0] 的意思就是从第一个开始,所有的数是从第一个开始放置的,到后面第 2^0-1 个元素的区间里面的最大值就是它本身,因为区间里面只有它这一个值。

而 f[1][2] 的意思就是说要求从第一个开始,到它后面第 2^2-1=3 元素的区间里面的最小值。

这个区间说白了就是包括第一个数,区间的长度为 2^j 的区间,因为减一就是去掉了第一个数字。

LC求的是已知它给出数列的长度n后,求出的以2为底,以n为指数的对数,因为f里面放置的是区间长度为1到LC的不同区间的最大值。而且这些不同的区间的起始的值也是不同的。

那怎么求呢?对于 f[i][j] 来说,我们只需要比较它的前一半区间,从i到第2^j-1再减一这个范围内的最大值,即 f[i][j-1] ,和i+(1<<(j-1))到 第2^j-1 再减一这个范围内的最大值进行比较就可以得到。

因为区间长度为二的 J 次方,所以一半就等于二的 J-1次方,这是第二个方括号里面的内容,然后就是右区间第一个方括号里面的内容,它的意思就是在原序号的基础上加上这个整区间的一半长度,因为(1<<(j-1)) 的意思就是 2的 j-1 次方,然后不用减一,就是这样。 

最后查询的时候,我们直接覆盖查询,也就是说,左区间的右边界可以大于右区间的左边界,半区间长度可以取成接近它本身的长度,2 ^ p -1 , p =log 2 ( r - l +1 ) 。

还有就是要求区间的长度是不能超过该区间的总长度的,为什么要说这个呢?是因为,双重 for 循环求f[][] 数组的时候,内层i的取值范围是 : i + 2 ^ j    -1  <=n    ,因为这是要求的区间长度。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1e6 + 9;
int f[maxn][41],a[maxn];
int main()
{
    int n, m, l, LC, p, r;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n;i++) {
        scanf("%d", &f[i][0]);
    }
    LC = (int)(log(n) / log(2));
    for (int j = 1; j <= LC;j++)
        for (int i = 1; i <= n - (1 << j) + 1;i++)
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    while (m--) {
        scanf("%d%d", &l, &r);
        p = (int)(log(r - l + 1) / log(2));
        printf("%d
",max(f[l][p],f[r-(1<<p)+1][p]));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xyqxyq/p/10211383.html