0
点赞
收藏
分享

微信扫一扫

0x06倍增-------《算法竞赛进阶指南》

夏沐沐 2022-04-13 阅读 64
c++算法

倍增即为划分上的成倍增长:

试求这样一个问题,有一个长度为N的数列A然后进行若干次询问,每次给出一个值T,求出最大的k满足从A[i]到A[k]的和小于T,同时要求的回答必须在线。

bf:每次枚举直到大于T为止.时间复杂度为n

二分:因为前缀和具有单调性,我们先预处理前缀和,然后二分k值这样复杂度为log(n)。

倍增:在每次T都很小的时候二分的优化,从开始枚举区间长度。

ST表

输入一串数字,给你 MM 个询问,每次询问就给你两个数字 X,Y,要求你说出 X 到 Y这段区间内的最大数。

输入格式

第一行两个整数 N,M 表示数字的个数和要询问的次数;

接下来一行为 N 个数;

接下来 M行,每行都有两个整数 X,Y

输出格式

输出共 M 行,每行输出一个数。

数据范围

1≤N≤105
1≤M≤106
1≤X≤Y≤N
数列中的数字均不超过2^31−1

输入样例:

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

输出样例:

5
8
#include <bits/stdc++.h>

#define PII pair<int,int>
#define ll long long
using namespace std;
const int N = 100005;
int a[N],f[N][20],k[N];
int n,M;

void init(){
    k[1] = 0,k[2] = 1;
    for(int i = 3; i <= N; ++i){
        k[i] = k[i / 2] + 1;
    }
}

void ST_prework(){
    for(int i = 1; i <= n; ++i)f[i][0] = a[i];
    int t = log(n) / log(2) + 1;
    for(int j = 1; j < t; ++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]);
        }
    }
}

int calc(int l, int r){
    int len = r - l + 1;
    return max(f[l][k[len]],f[r - (1 << k[len]) + 1][k[len]]);
}


int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    init();
    cin >> n >> M;
    for(int i = 1; i <= n; ++i){
        cin >> a[i];
    }
    ST_prework();
    while(M--){
        int x,y;
        cin >> x >> y;
        cout << calc(x,y) << '\n';
    }
    return 0;
}
举报

相关推荐

0 条评论