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[i][0];
    }

初始化

----------------------------------

建立:

我们维护的是长度为2的整数

幂长的区间

对于任何一个区间,我们考虑把他平分成两部分

例如对于st[i][j],我们把它分成st[i][j-1]和st[i+(1<<(j-1)][j-1]两部分,即为分成一半

然后取他们的最值就行了

    for(int j=1;j<=21;j++)
        for(int i=1;i+(1<<j)-1<=n;++i)
            st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);

建立

-----------------------------

查询:

我们查询的区间长度当然不会全是2的整数次幂

然而我们又不能查大了(越界)

就只能查小的,这样就覆盖不了整个区间,怎么办呢?

我们可以从左右端点分别查询2^k的长度,这样就可以保证覆盖掉整个区间又不越界了

    for(int i=1;i<=m;++i){
        scanf("%d%d",&l,&r);
        int k=log2(r-l+1);
        printf("%d\n",max(st[l][k],st[r-(1<<k)+1][k]));
    }

查询

---------------------------

完整代码:

 1 #include<iostream>
 2 #include<cmath>
 3 #include<cstdio>
 4 using namespace std;
 5 int st[1000001][50];
 6 int l,r;
 7 int n,m;
 8 int main(){
 9     scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;++i){
11         cin>>st[i][0];
12     }
13     for(int j=1;j<=21;j++)
14         for(int i=1;i+(1<<j)-1<=n;++i)
15             st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
16     for(int i=1;i<=m;++i){
17         scanf("%d%d",&l,&r);
18         int k=log2(r-l+1);
19         printf("%d\n",max(st[l][k],st[r-(1<<k)+1][k]));
20     }
21     return 0;
22 }

Ac

原文地址:https://www.cnblogs.com/For-Miku/p/11336052.html

时间: 2024-10-09 17:41:12

P3865 【模板】ST表的相关文章

[模板]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^

洛谷—— 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 

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

【模板】ST表 洛谷P1816 忠诚

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

ST表——模板(luogu3865)

题目背景 这是一道ST表经典题--静态区间最大值 请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1) 题目描述 给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值. 输入输出格式 输入格式: 第一行包含两个整数 N, M ,分别表示数列的长度和询问的个数. 第二行包含 N 个整数(记为 ai),依次表示数列的第 i 项. 接下来 M 行,每行包含两个整数 li, ri,表示查询的区间为 [ li, ri ] 输出格式: 输出包含 M

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

RMQ问题 - ST表的简单应用

2017-08-26 22:25:57 writer:pprp 题意很简单,给你一串数字,问你给定区间中最大值减去给定区间中的最小值是多少? 用ST表即可实现 一开始无脑套模板,找了最大值,找了最小值,分别用两个函数实现,实际上十分冗余 所以TLE了 之后改成一个函数中同时处理最大值和最小值,就可以了 AC代码如下: /* @theme:poj 3264 @writer:pprp @declare:ST表(sparse table)稀疏表,用动态规划的思想来解决RMQ问题: @date:2017

【cogs58】延绵的山峰【st表】

问题描述 有一座延绵不断.跌宕起伏的山,最低处海拔为0,最高处海拔不超过8848米,从这座山的一端走到另一端的过程中,每走1米海拔就升高或降低1米.有Q个登山队计划在这座山的不同区段登山,当他们攀到各自区段的最高峰时,就会插上队旗.请你写一个程序找出他们插旗的高度. 输入文件 第1行,一个整数N(N<=10^6),表示山两端的跨度. 接下来N+1行,每行一个非负整数Hi,表示该位置的海拔高度,其中H0=Hn=0. 然后是一个正整数Q(Q<=7000),表示登山队的数量. 接下来Q行,每行两个数

算法详解——st表

st表是解决区间RMQ(区间最值问题)的一类算法,时间复杂度为O(nlogn)的预处理和O(1)的查询,其主要运用了类似倍增的思想... 总体来说,st表的用处还是挺大的,代码也比较短,容易记... st表 若现在给定一个长度为n的序列A,每次给定两个数l,r,求出A[l]~A[r]中的最大值... 那么我们考虑怎么做,首先是朴素做法,每次询问最大值时用for循环从l到r跑一遍,每次循环复杂度为O(r - l) 那有没有一种算法可以让我们以O(1)的复杂度就知道最大值呢? 这时我们引进st表算法