模板 - 数据结构 - ST表

区间最大值,nlogn预处理,1查询,不能动态修改。

令 $f[i][j]$ 表示 $[i,i+2^j-1]$ 的最大值。

显然, $f[i][0]=a[i]$ 。

根据定义式,写出状态转移方程: $f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1])$ 。

我们可以这么理解:将区间 $[i,i+2^j-1]$ 分成相同的两部分

中点即为 $(i+(i+2^j-1))/2=i+2^{j-1}-1/2$

所以 $[i,i+2^j-1]$ 可以分成 $[i,i+2^{j-1}-1]$ 和 $[i+2^j,i+2^j-1]$

对于每个询问 $[x,y]$ ,我们把它分成两部分 $f[x][s],f[y-2^s+1][s]$

其中 $s=log_2(y-x+1)$ ,虽然这两个区间有重叠,但是重叠不会影响区间的最大值

#include <bits/stdc++.h>
using namespace std;
const int logn = 21;
const int maxn = 2000001;
long long a[maxn], f[maxn][logn], Logn[maxn];
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while (c < ‘0‘ || c > ‘9‘) {
        if (c == ‘-‘)
            f = -1;
        c = getchar();
    }
    while (c >= ‘0‘ && c <= ‘9‘) {
        x = x * 10 + c - ‘0‘;
        c = getchar();
    }
    return x * f;
}
void pre() {
    Logn[1] = 0;
    Logn[2] = 1;
    for (int i = 3; i <= maxn; i++) {
        Logn[i] = Logn[i / 2] + 1;
    }
}
int main() {
    int n = read(), m = read();
    for (int i = 1; i <= m; i++)
        f[i][0] = read();
    pre();
    for (int j = 1; j <= logn; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    for (int i = 1; i <= m; i++) {
        int x = read(), y = read();
        int s = Logn[y - x + 1];
        printf("%d\n", max(f[x][s], f[y - (1 << s) + 1][s]));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Yinku/p/10472788.html

时间: 2024-08-01 16:39:19

模板 - 数据结构 - ST表的相关文章

【模板】ST表 洛谷P1816 忠诚

P1816 忠诚 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于 管家聪明能干,因而管家总是让财主十分满意.但是由于一些人的挑拨,财主还是对管家产生了怀疑.于是他决定用一种特别的方法来判断管家的忠诚,他把每次的 账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题. 输入输出格式 输入格式: 输入中第一行有两个数m,n表示有m(m<=100000

洛谷—— P3865 【模板】ST表

https://www.luogu.org/problemnew/show/P3865 题目背景 这是一道ST表经典题——静态区间最大值 请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1)O(1) 题目描述 给定一个长度为 NN 的数列,和 MM 次询问,求出每一次询问的区间内数字的最大值. 输入输出格式 输入格式: 第一行包含两个整数 N, MN,M ,分别表示数列的长度和询问的个数. 第二行包含 NN 个整数(记为 a_iai?),依次表示数列的第 ii 

P3865 【模板】ST表

----------------------------------- 链接:P3865 ----------------------------------- st表是一个用来解决RMQ问题的表 st表是一个二维数组,表示的是i~i+2^j-1范围的最值 (这东西和区间DP好像) ---------------------------------- 初始化: 因为2^0=1; 所以说st[i][0]存的就是i~i范围的最值(就是他自己) for(int i=1;i<=n;++i){ cin>

【模板】 ST表

某dalao的代码 1 void ST(int n) { 2 for (int i = 1; i <= n; i++) 3 dp[i][0] = A[i]; 4 for (int j = 1; (1 << j) <= n; j++) { 5 for (int i = 1; i + (1 << j) - 1 <= n; i++) { 6 dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1])

【模板】ST表

#include <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n, m, f[100010][21]; void init() { for (int j = 1; j <= 20; j++) for (int i = 1; i + (1 << j) -

RMQ与st表

模板题 P3865 [模板]ST表 代码 实质也是DP,利用倍增获取从i开始长度为\(2^0,2^1,2^2-2^j\)的区间内的最大值. 这样对于任意区间\([l,r]\)都有,令\(dis=r-1+1\)则有\(k_0=2^c,2^{k_0}≤dis≤2^{k_0+1}\)这样在区间\([l,l+k0-1],[r-k0+1,r]\)完全覆盖了这个区域(中间可能有重叠) #include <iostream> #include <cmath> #include <cstdi

HDU6356:Glad You Came ST表的巧妙利用

首先题意是告诉你要进行m次区间赋最值操作,要求你求出每一个值最后的大小,这题的难点在于查询m的次数是非常多的,高达1e8,所以你想用线段树边修改边查询是不可能的,(因为是随机出的数据,所以有一些剪枝被卡过去了,我女朋友就是这么过的,好气啊!!!)所以这个题用了我觉得很少见的一类数据结构ST表,ST的特征是可以用ologn的时间内建表,然后每次查询都是o(1)的,所以就是很适合这道题的特点了,因为这道题目也是有着多查询,和求最值的,所以我们使用了反着建立ST表的方法去实现这个东西,也是类似于dp的

[模板]ST表浅析

ST表,稀疏表,用于求解经典的RMQ问题.即区间最值问题. Problem: 给定n个数和q个询问,对于给定的每个询问有l,r,求区间[l,r]的最大值.. Solution: 主要思想是倍增和区间dp. 状态:dp[i][j] 为闭区间[i,i+2^j-1]的最值. 这个状态与转移方程的关系很大,即闭区间的范围涉及到了转移方程的简便性. 转移方程:dp[i][j]=max(dp[i][j-1],dp[i+2^(j-1)][j-1]). 这是显然的,但这里有个细节:第一个项的范围为[i,i+2^

ST表竞赛模板

void RMQ_init(){//ST表的创建模板 for(int i=0;i<n;i++) d[i][0]=mo[i]; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++){ d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } } int RMQ_min(int L,int R){//区间最小.大值 int k=0; while((1<&l