当前位置: 首页 > news >正文

ST算法和ST表

目录

一、解决什么类型的问题

二、ST算法原理

三、实现


一、解决什么类型的问题

对于一个数列a,现要进行k次操作:

给定l和r,输出l和r之间的最大值

很容易想暴力,总时间差不多是O(r-l)*k

二、ST算法原理

因为任意一个自然数都可以被表示为数个2的n次幂的和(废话),所以我们可以通过在输入数列a时进行一次预处理,将数列分为n个小段,对于每一个小段求出最大值(有点像最优子结构的意思),最后合并成原来的数列。你可能会觉得他会漏掉一部分区间,但是任意区间都可以通过两个二次幂的区间运算得到

比如[1,3]=max([1,2],[2,3])

三、实现

先设f[i][j]表示数列a中从i开始的2^j个数的最大值,其中f[i][0]=a[i],因为f[i][0]表示a[i]到a[i]间的最大值。

在预处理,也就是地推时,我们使用倍增的思想

f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);

即从=以f[i][j] 为分界线,将他左边分成一段,再把他的右边分成一段.

f[i][j-1]的i表示i为起点,2^{j-1}是长度。

f[i+(1<<(j-1))][j-1]中:

        i+(1<<(j-1)) 表示右区间的起点也就是左区间的终点+1

来看一道模板题:

P3865 【模板】ST 表 && RMQ 问题 - 洛谷

先写读入和输出部分 


int main(){n=read();m=read();for(int i=1;i<=n;++i){a[i]=read();}pre_work();//预处理函数for(int i=1;i<=m;++i){int a,b;a=read();b=read();printf("%d\n",ST_query(a,b));}return 0;
}

定义 ST_query(a,b)返回[a,b]区间的最大值

预处理

接下来是最重要的预处理函数

void pre_work(){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]);}}
}


首先确定dp边界,就上上面说的f[i][0]的最大值就是a[i]。赋初值

随后确定循环次数,数列的总长度为n,使用 \frac{log(n)}{log(2)}+1计算出需要处理的区间长度的最大二进制幂次加 1,实际意义表示原来的数列长度分解为k个2的n次方后的2的指数,具体来说是

n=8,计算得k=4,表示循环变量会经过2^{0} ,2^{1},2^{2},2^{3}中的0,1,2,3,以此保证以2^{j-1}为长度划分序列不会超过序列的原长度。

查找

int ST_query(int l,int r){int k=log(r-l+1)/log(2);return max(f[l][k],f[r-(1<<k)+1][k]);
}

计算出一个k,使得2^{k} 不能超过数列的最大长度

但是两段之间不能有空隙,如果漏掉了一些数,就不能保证是最大值

所以有空隙就不行,但是有重叠没关系

但现在我们知道1区间的起点,但问题是我们并不知道2区间的长度。如果从1区间的起点加上1区间的长度,有极大概率超出原数列的长度。所以我们采取一种措施,就是从数列的末端向前移动2^{j-1}个单位,以此查找

Talk is cheap,show me the code 

AC Code:

#include<bits/stdc++.h>
using namespace std;
int const N=1e5+10;
int a[N],f[N][32];
int n,m;
int read(){int s=0,fl=1;char w=getchar();while(w>'9'||w<'0'){if(w=='-')fl=-1;w=getchar();}while(w<='9'&&w>='0'){s=s*10+(w^48);w=getchar();}return fl*s;
}
void pre_work(){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 ST_query(int l,int r){int k=log(r-l+1)/log(2);return max(f[l][k],f[r-(1<<k)+1][k]);
}int main(){n=read();m=read();for(int i=1;i<=n;++i){a[i]=read();}pre_work();for(int i=1;i<=m;++i){int a,b;a=read();b=read();printf("%d\n",ST_query(a,b));}return 0;
}

 

 

http://www.dtcms.com/a/282140.html

相关文章:

  • 在Next.js里玩转pdf预览
  • django在线音乐数据采集-22647
  • Django+Celery 进阶:Celery可视化监控与排错
  • JobSet:Kubernetes 分布式任务编排的统一解决方案
  • flink sql读hive catalog数据,将string类型的时间戳数据排序后写入kafka,如何保障写入kafka的数据是有序的
  • 从零开始的云计算生活——番外4,使用 Keepalived 实现 MySQL 高可用
  • Django 接口自动化测试平台实现(一)
  • 蓝光三维扫描技术:汽车轮毂轴承模具检测的高效解决方案
  • 【tower】Rust tower库原理详解以及axum限流实战
  • 在新闻资讯 APP 底部切换不同类型界面,部分界面可以通过 ViewPager 实现滑动切换
  • 枫清科技参编的《人工智能知识工程指南(1.0)》发布
  • 压力测试Apache Bench(ab)
  • 从缓存 CAS 看Kimi K2使用的MuonClip优化器
  • 电力政策解读:山东电网新型储能集中调用的能源管理系统实现点
  • LinkedList集合源码解析
  • 超级天才如何批量制造?天才成长引擎模型:超级天才 = (学习速度泛化力 × 创造力 × 专注力) × 驱动力
  • python基础②-数据结构
  • AlpineLinux的用户管理
  • conda activate 时报错: CondaError: Run ‘conda init‘ before ‘conda activate‘
  • XC7A75T‑2FGG484I Xilinx Artix‑7 FPGA AMD
  • go项目实战
  • 深入解析Linux进程地址空间与虚拟内存管理
  • 虚拟内存管理--请求分页管理方式
  • 15.dispatcherRunner启动
  • 图机器学习(10)——监督学习中的图神经网络
  • LLM大语言模型不适合统计算数,可以让大模型根据数据自己建表、插入数据、编写查询sql统计
  • ether.js的calldata
  • 探索阿里云DMS:解锁高效数据管理新姿势
  • 【WRFDA数据教程第一期】LITTLE_R 格式详细介绍
  • 常用 Benchmark 总结-GPT 4.1、GPT 4.5、DeepSeek模型