C++题解:静态区间最大值

news2024/11/23 15:19:02

题目链接

P3865 ST 表

题目描述

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

请注意最大数据时限只有 0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O ( 1 ) O(1) O(1)。若使用更高时间复杂度算法不保证能通过。

如果您认为您的代码时间复杂度正确但是 TLE,可以尝试使用快速读入:

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

函数返回值为读入的第一个整数。

快速读入作用仅为加快读入,并非强制使用。

题目描述

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

输入格式

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

第二行包含 N N N 个整数(记为 a i a_i ai),依次表示数列的第 i i i 项。

接下来 M M M 行,每行包含两个整数 l i , r i l_i,r_i li,ri,表示查询的区间为 [ l i , r i ] [l_i,r_i] [li,ri]

输出格式

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

样例 #1

样例输入 #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 % 30\% 30% 的数据,满足 1 ≤ N , M ≤ 10 1\le N,M\le 10 1N,M10

对于 70 % 70\% 70% 的数据,满足 1 ≤ N , M ≤ 10 5 1\le N,M\le {10}^5 1N,M105

对于 100 % 100\% 100% 的数据,满足 1 ≤ N ≤ 10 5 1\le N\le {10}^5 1N105 1 ≤ M ≤ 2 × 10 6 1\le M\le 2\times{10}^6 1M2×106 a i ∈ [ 0 , 10 9 ] a_i\in[0,{10}^9] ai[0,109] 1 ≤ l i ≤ r i ≤ N 1\le l_i\le r_i\le N 1liriN

算法思想:ST表

先来了解几个概念:倍增,ST表,RMQ

倍增

倍增就是成倍增加。若问题的状态空间特别大,则一步步递推求解时间复杂度太高,可以通过倍增的思想,只考察 2 2 2的整数次幂位置, 2 , 4 , 8... 2,4,8... 2,4,8...,快速缩小求解范围,知道找到解。

ST表

ST(Sparse Table,稀疏表)算法采用了倍增的思想,在 O ( n l o g n ) O(nlogn) O(nlogn)时间里构造一个二维表,可以在 O ( 1 ) O(1) O(1)的时间查找 [ L , R ] [L, R] [L,R]区间的最值,即RMQ(Range Minimum/Maximum Query)问题。

基本原理

f [ i , j ] f[i,j] f[i,j]表示区间 [ i , i + 2 j − 1 ] [i,i + 2^j-1] [i,i+2j1]的最值,即从 i i i开始,长度为 2 j 2^j 2j的区间的最大值或者最小值,如下图所示:
在这里插入图片描述
长度为 2 j 2^j 2j的区间可以被分成两个长度为 2 j − 1 2^{j-1} 2j1的子区间,然后可以得到递推公式: f [ i ] [ j ] = m a x { f [ i , j − 1 ] , f [ i + 2 j − 1 , j − 1 ] } f[i][j]=max\{f[i,j-1],f[i+2^{j-1},j-1]\} f[i][j]=max{f[i,j1],f[i+2j1,j1]}。如下图所示:
在这里插入图片描述

创建ST表

f [ i , j ] f[i, j] f[i,j]表示区间 [ i , i + 2 j − 1 ] [i, i+2^j-1] [i,i+2j1]的最值,区间长度为 2 j 2^j 2j,若数组的长度 n n n,最大区间长度 2 j ≤ n 2^j\le n 2jn,则 j ≤ ⌊ l o g 2 n ⌋ j\le \lfloor{log_2n}\rfloor jlog2n

void create() {
    //初始状态
    //f[i][0]表示从i开始长度为2^0的区间最值为a[i]本身
    for(int i = 1; i <= n; i ++) f[i][0] = a[i];
    int k = log2(n);
    //枚举区间长度的指数j
    for(int j = 1; j <= k; 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]);
}

例如,有10个元素的数组 a [ 1...10 ] = { 5 , 3 , 2 , 7 , 9 , 8 , 10 , 1 , 3 , 15 } a[1...10]=\{5,3,2,7,9, 8,10,1,3,15\} a[1...10]={5,3,2,7,9,8,10,1,3,15}
在这里插入图片描述

查询ST表

查询区间 [ L , R ] [L,R] [L,R]的最值,首先需要计算的区间长度为 R − L + 1 R-L+1 RL+1,那么 2 j ≤ R − L + 1 2^j\le R-L+1 2jRL+1,因此设 j = l o g 2 ( R − L + 1 ) j=log_2(R-L+1) j=log2(RL+1)
那么要查询区间 [ L , R ] [L,R] [L,R]的最值,则可以将查询区间分为两个,取两个区间的最值即可。这两个区间分别为:

  • L L L向后的 2 j 2^j 2j个数
  • R R R向前的 2 j 2^j 2j个数

这两个区间可能有重叠,但对求最值没有影响。

//利用ST表查询区间[L,R]的最大值
int query(int L, int R) {
    int j = log2(R - L + 1);
    return max(f[L][j], f[R - (1 << j) + 1][j]);
}

时间复杂度

  • 创建ST表: O ( n l o g n ) O(nlogn) O(nlogn)
  • 查询ST表: O ( 1 ) O(1) O(1)

代码实现

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1e5 + 10, M = 100;
int n, a[N], f[N][M];
//创建ST表
void create() {
    //初始状态
    //f[i][0]表示从i开始长度为2^0的区间最值为a[i]本身
    for(int i = 1; i <= n; i ++) f[i][0] = a[i];
    int k = log2(n);
    //枚举区间长度指数j
    for(int j = 1; j <= k; 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]);
}
//利用ST表查询区间[L,R]的最大值
int query(int L, int R) {
    int j = log2(R - L + 1);
    return max(f[L][j], f[R - (1 << j) + 1][j]);
}
int main()
{
    int m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) scanf("%d", a + i);;
    create();
    while(m --) {
        int L, R;
        scanf("%d%d", &L, &R);
        printf("%d\n", query(L, R));
    }
}

总结

RMQ(区间最值查询)问题有多种解决方法:

  • ST表预处理的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),查询时间复杂度为: O ( 1 ) O(1) O(1),但是只能静态查询,不支持修改。
  • 线段树处理的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),查询时间复杂度为: O ( l o g n ) O(logn) O(logn),支持实时修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/491036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java版企业电子招投标采购系统源码——功能模块功能描述+数字化采购管理 采购招投标

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…

ansible常见概念总结

目录 1、play和playbook和role 2、幂等性 3、清单 4、配置文件(ansible.cfg) 5、变量 5.1 在playbook中使用变量&#xff1a; 5.2 在playbook中使用变量文件&#xff1a; 6、事实 7、循环 8、处理程序 9、块 10、动态清单文件 11、角色 1、play和playbook和role …

本地事务,分布式事务(Seata)

本地事务 四大特性ACID A:原子性(Atomicity)&#xff1a;事务是不可分割的最小操作但愿&#xff0c;要么全部成功&#xff0c;要么全部失败 C:一致性(Consistency)&#xff1a;事务完成时&#xff0c;必须使所有数据都保持一致状态 l:隔离性(Isolation)&#xff1a;数据库系统…

[架构之路-188]-《软考-系统分析师》-3-操作系统 - 图解页面替换算法LRU、LFU

目录 一、内存置换算法的缘由 二、算法详解 2.1 最佳页面置换算法&#xff08;OPT&#xff09; 》 理论上的最优&#xff0c;实际无法保证 2.2 先进先出置换算法&#xff08;FIFO&#xff09;-- 按加载时间/最早访问时间排序 2.3 最近最久未使用的置换算法&#xff08;L…

JDK、JRE 和 JVM 之间的区别

虚拟机 JVM&#xff08;Java Virtual Machine&#xff09;是一个抽象机器。之所以称为虚拟机&#xff0c;是因为它在物理上并不存在。它是一个规范&#xff0c;它提供了一个可以在其中执行 Java 字节码的运行时环境。它还可以运行那些用其他语言编写并编译为 Java 字节码的程序…

c++详解之右值引用

右值引用&#xff1a; 右值引用是C11引入的一个新特性&#xff0c;它允许我们显式地将一个表达式标记为右值&#xff0c;从而可以使用移动语义进行优化。 在C中&#xff0c;每个表达式都是要么是左值&#xff0c;要么是右值。左值是指可以取地址的表达式&#xff0c;例如变量…

linux 系统下gcc

linux c gcc gcc编译可以执行4步骤&#xff1a;预处理、编译、汇编、链接 预处理 gcc -E hello.c----->hello.i 展开宏、头文件&#xff0c;替换条件编译&#xff0c;删除注释、空行、空白 编译 gcc -S hello.i------>hello.s 检查语法规范 汇编 gcc -c hello.…

网络安全行业就职岗位有哪些?

网络安全作为目前最火的行业之一&#xff0c;它的细分方向很多。下面介绍一下网络安全主要的方向岗位有哪些&#xff0c;以及职责是什么&#xff1f; 一、安全规划与设计方向 岗位名称&#xff1a;系统安全需求分析师。 岗位职责&#xff1a;负责对目标对象需要达到的安全目标…

DIN11 FVI频率脉冲信号转电压电流信号隔离转换模块变换器

主要特性 将单位脉冲信号转换成直流电压或电流信号。 精度等级&#xff1a;0.1 级、0.2 级、0.5 级。产品出厂前已检验校正&#xff0c;用户可以直接使用。 国际标准信号输入: 0-5KHz/0-10KHz/1-5KHz等 0-5V/0-10V/1-5V 等电压信号,0-10mA/0-20mA/4-20mA 等电流信号。 …

新港转债,百洋转债上市价格预测

新港转债 基本信息 转债名称&#xff1a;新港转债&#xff0c;评级&#xff1a;AA-&#xff0c;发行规模&#xff1a;3.69135亿元。 正股名称&#xff1a;新中港&#xff0c;今日收盘价&#xff1a;8.67元&#xff0c;转股价格&#xff1a;9.18元。 当前转股价值 转债面值 / 转…

Java设计模式-代理模式

简介 代理模式是一种结构型设计模式&#xff0c;它可以让我们通过一个代理对象来访问一个真实的目标对象&#xff0c;从而实现对目标对象的功能扩展或保护。代理模式的主要角色有三个&#xff1a; 抽象主题&#xff08;Subject&#xff09;&#xff1a;定义了真实主题和代理主…

Prompt 技巧指南-让 ChatGPT 回答准确十倍!

出品人&#xff1a;Towhee 技术团队 作者&#xff1a;张晨 随着 ChatGPT 等大型语言模型 (LLM)的兴起&#xff0c;人们慢慢发现&#xff0c;怎么样向 LLM 提问、以什么技巧提问&#xff0c;是获得更加准确的回答的关键&#xff0c;也由此产生了提示工程这个全新的领域。 提示工…

JavaScript实现输入班级人数和成绩后,输出总成绩、平均成绩、最高分、最低分的代码

以下为实现输入班级人数和成绩输出总成绩、平均成绩、最高分、最低分的代码和运行截图 目录 前言 一、实现输入班级人数和成绩&#xff0c;输出总成绩、平均成绩、最高分、最低分的代码 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有…

JavaWeb《后端内容:1.Tomcat--Servlet--Thymeleaf》

目录 1. 基础概念 1.1 BS架构和CS架构 1.2 Tomcat图解 2.TomCat 2.1 IDEA配置web项目和tomcat 2.2 idea启动TomCat因为端口号失败的问题 3.Servlet使用流程 3.1 Servlet简单图解 3.2 Servlet导入依赖 3.3 编写Servlet和add.html 3.4 试着使用Jdbc和Dao层连接水果库存…

超细Redis(一)

目录 概述 Redis是什么&#xff1f; Redis能干嘛&#xff1f; 特性 如何学习 Linux安装 测试性能 概述 Redis是什么&#xff1f; Redis &#xff08;Remote Dictionary Server&#xff09;,即远程字典服务 是一个开源使用ANSI C语言编写、支持网络、可基于内存亦可持…

阿里版ChatGPT——通义千问,开箱初体验

所有行业、所有应用、所有服务都值得基于新型人工智能技术重做一遍&#xff0c;在带来创造性客户体验的同时&#xff0c;生产范式、工作范式、生活范式也将发生变化。——阿里集团董事会主席兼CEO 张勇 2023阿里云峰会上&#xff0c;通义千问大语言模型对外发布&#xff0c;宣称…

【语义分割】LinkNet 从0到1 和代码实现

文章目录 前言1.网络结构1.1 网络结构示意图1.2 创建LinkNet模型 2.代码 前言 已经有了U-net了&#xff0c;为什么需要linkNet&#xff1f; unet见这个文章【语义分割】unet结构和代码实现:https://blog.csdn.net/weixin_40293999/article/details/129648032 它引入了resNet&a…

“SDL 入门指南:了解 SDL,快速上手 SDL 的安装和配置”——VS2022

前言 欢迎来到小K的SDL专栏第一小节&#xff0c;本节为大家介绍一下SDL是什么&#xff0c;能做什么&#xff0c;可以在哪些平台运行以及SDL的安装和VS2022配置SDL、导出模板、cmake运行SDL&#xff0c;同时我也会在资源里为大家上传SDL2.26的安装包&#xff0c;为在github上下载…

扫地机洗地机语音芯片ic一体方案 WTV多功能语音芯片

​随着智能家居的快速普及&#xff0c;扫拖一体机语音芯片ic逐渐成为了家庭清洁的必备之物。在智能家居、商业清洁服务、医院清洁服务、办公室清洁等领域得到广泛应用&#xff1b;而语音芯片方案的应用让清洁机器设备使用起来更加方便和智能化。 编辑搜图 目前大多数扫地机厂家…

2023/5/4总结

刷题&#xff1a; 第二周任务 - Virtual Judge (vjudge.net) 这一题用到了素筛,然后穷举即可 #include<stdio.h> #define Maxsize 500000 int a[Maxsize]; long long b[Maxsize]; long long max0; int sushu() {a[0]a[1]0;int i,j,k;for(i2,k0;i<Maxsize;i){if(a[i…