ST表(动态规划倍增思路离线维护区间极值问题)

这篇博客介绍了如何使用动态规划实现区间最大值查询。代码中定义了RMQ函数,通过预处理log2(N)并利用倍增策略来高效地计算给定区间内的最大值。在解决实际问题时,该方法能够快速查询数组中的最大值,对于处理大规模数据尤为有效。

Acwing:天才的记忆

板子复制: 板子复制: 板子复制:

int f[N][18], a[N];
int lg[N];//预处理log2(N)

void RMQ(int nn) {
    for (int j = 0; (1 << j) <= nn; j++)
        for (int i = 1; i + (1 << j) - 1 <= nn; i++)
            if (!j) {
                f[i][j] = a[i];
                if (i > 1)lg[i] = lg[i >> 1] + 1;
            }
            else f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}

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

void solve() {
    cin >> n;
    forr(i, 1, n)cin >> a[i];
    RMQ(n);

    cin >> m;
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        cout << query(l, r) << endl;
    }
}

注释 C o d e : 注释Code: 注释Code

#include<bits/stdc++.h>
#include<unordered_map>
#define debug cout << "debug---  "
#define debug_ cout << "\n---debug---\n"
#define oper(a) operator<(const a& ee)const
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define all(a) a.begin(),a.end()
#define sz(a) (int)a.size()
#define endl "\n"
#define ul (u << 1)
#define ur (u << 1 | 1)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<ll, int> PII;

const int N = 2e5 + 10, M = 2e3 + 10, mod = 1e9 + 7;
int INF = 0x3f3f3f3f; ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, B = 10, ki;

int f[N][18], a[N];
int lg[N];//预处理log2(N)是多少,可以加速很多 

void RMQ(int nn) { //传入长度,自动维护 j 大小
 	//倍增动态规划
    //f[i][j]维护 i 点开始长度为 2^j 段的最大值
    //其他都是模板,背过或者笔记摘抄
    for (int j = 0; (1 << j) <= nn; j++)
        for (int i = 1; i + (1 << j) - 1 <= nn; i++)
            if (!j) {
                f[i][j] = a[i];
                if (i > 1)lg[i] = lg[i >> 1] + 1;
            }
            else f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}

int query(int l, int r) {
    int k = lg[r - l + 1];
    return max(f[l][k], f[r - (1 << k) + 1][k]);

    //找一个最大的不会超过长度(下取整)的次方数 k
    //前后两段取极值,包含了区间
}

void solve() {
    cin >> n;
    forr(i, 1, n)cin >> a[i];
    RMQ(n);

    cin >> m;
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        cout << query(l, r) << endl;
    }
}

int main() {
    cinios;
    int T = 1;
    for (int t = 1; t <= T; t++) {
        solve();
    }
    return 0;
}
/*
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值