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

RMQ与LCA学习笔记

在开始之前先提一下RMQ与LCA这两个东西有什么关系
对于一个序列,对它构建出一颗笛卡尔树之后,两个点的LCA就是原序列中这两个点之间的最大值/最小值(取决于建树时的比较方式)
而对于一棵树,求出来他的欧拉序之后,两个点的LCA,就是两个点在欧拉序第一次出现的位置之间的深度最小值的点
所以LCA问题和RMQ问题是可以相互转换的

RMQ

RMQ 即区间最值问题,根据情景的不同,我们可以给出不同的方法

静态区间最值问题

ST表

ST表,是一个处理静态可重复贡献问题的利器,区间最值显然是可以重复贡献的。
\(st_{i,k}\) 表示原序列中 \([i,i+2^k-1]\) 中的最值,显然初始化是 \(st_{i,0}=a[i]\)
我们可以将 \([i,i+2^k-1]\) 拆分成 \([i,i+2^{k-1}-1]\)\([i+2^{k-1},i+2^{k}-1]\) ,这两个区间中的最值显然是 \(st_{i,k-1}\)\(st_{i+2^{k-1},k-1}\)
所以我们从小到大枚举 \(k\) ,用 \(st_{i,k-1}\)\(st_{i+2^{k-1},k-1}\) 更新 \(st_{i,k}\)

for(int i=1;i<=n;i++)f[i][0]=read();
int t=log2(n);
for(int i=1;i<=t;i++){for(int k=1;k<=n-(1<<i)+1;k++){f[k][i]=max(f[k][i-1],f[k+(1<<(i-1))][i-1]);}
}//这里的i,k与上文中是反过来的

查询时,需要将 \([l,r]\) 拆成两个区间,使它们覆盖整个 \([l,r]\) ,可以发现 \(st_{l,\lfloor log_{2}{r-l+1}\rfloor}\) \(st_{r-2^{\lfloor log_{2}{r-l+1}\rfloor}+1,\lfloor log_{2}{r-l+1}\rfloor}\) 可以覆盖整个区间。

for(int i=1;i<=m;i++){int l,r;l=read();r=read();int k=log2(r-l+1);write(max(f[l][k],f[r-(1<<k)+1][k]));puts("");
}

预处理时间复杂度为 \(O(nlogn)\) ,单次查询复杂度为 \(O(1)\)

Method of Four Russians

就是人们常说的“四毛子”,这个算法在ST表的基础上进行了优化。
对序列进行分块,设块长为 \(B\) ,在块间建立ST表,时间复杂度为 \(O(\frac{N}{B}log{\frac{N}{B}})\),在块内建立ST表,时间复杂度为 \(O(\frac{N}{B}Blog{B})\).
查询时,若 \(l,r\) 在同一个块内,直接用块内的ST表查询,若 \(l,r\) 不在同一个块内,那么对于散块用块内的ST表查询,对于整块用块间的ST表查询。查询时间复杂度为 \(O(1)\)
\(B\)\(O(log_2{n})\) 时,预处理时间复杂度是 \(O(nloglogn)\)

struct FR{int ST[N/len+5][log2(N/len)+5],st[N][log2(len)+5];struct block{int l,r,ma;}b[N/len+5];void init(){for(int i=1;i<=id(n);i++){b[i].l=b[i-1].r+1;b[i].r=i*len;b[i].ma=0;}b[id(n)].r=n;for(int i=1;i<=id(n);i++){int t=log2(b[i].r-b[i].l+1);for(int k=b[i].l;k<=b[i].r;k++)st[k][0]=a[k],b[i].ma=max(b[i].ma,a[k]);for(int k=1;k<=t;k++){for(int j=b[i].l;j+(1<<k)-1<=b[i].r;j++){st[j][k]=max(st[j][k-1],st[j+(1<<(k-1))][k-1]);}				}}for(int i=1;i<=id(n);i++)ST[i][0]=b[i].ma;int t=log2(id(n));for(int i=1;i<=t;i++){for(int k=1;k+(1<<i)-1<=id(n);k++){ST[k][i]=max(ST[k][i-1],ST[k+(1<<(i-1))][i-1]);}}}int ask(int l,int r){int p=id(l),q=id(r);if(p==q){int t=log2(r-l+1);return max(st[l][t],st[r-(1<<t)+1][t]);}int x,y,z;int t=log2(b[p].r-l+1);x=max(st[l][t],st[b[p].r-(1<<t)+1][t]);t=log2(r-b[q].l+1);y=max(st[b[q].l][t],st[r-(1<<t)+1][t]);if(p+1>q-1)return max(x,y);t=log2(q-1-(p+1)+1);z=max(ST[p+1][t],ST[(q-1)-(1<<t)+1][t]);return max(x,max(y,z));}
}f;

但由于每次查询会使用3次ST表,所以常数会比直接建ST表大很多,在 \(n\) 较小的时候还是直接写ST表好

优化

\(l,r\) 不在一个块内时,考虑对于散块的查询,我们只需要考虑一个前缀或后缀的贡献就可以了,这样就可以将ST表调用次数降低到1次

O(N)-O(1)Rmq

四毛子的瓶颈在于当 \(l,r\) 在同一块时,没法做到快速处理。
这里给出一个基于状压的线性RMQ的做法
……

http://www.hskmm.com/?act=detail&tid=28255

相关文章:

  • mamba-硬件感知算法
  • Java1
  • 完整教程:lua代码解析1
  • 二维数点
  • gitee和github如何修改仓库名并且保持与原远程仓库的连接?(手把手教学) - 实践
  • 2025.10.10总结 - A
  • [20251010]建立完善tpt的prr.sql脚本.txt
  • 第十一篇
  • testtest
  • 题解:AT_arc138_f [ARC138F] KD Tree
  • SP33 TRIP - Trip 个人题解
  • 经营不是老板一个人的事 - 智慧园区
  • Codeforces Round 1051 (Div. 2)[A ~E]
  • 如何在 Spring Boot 应用中配置多个 Spring AI 的 LLM 客户端
  • 使用eBPF技术保护FastAPI安全
  • 项目案例作业2:对案例进行面向对象分析
  • JavaSE
  • CF2064E Mycraft Sand Sort
  • Servlet笔记
  • 第一个博客
  • k8s 主节点重启后 从节点 get 异常 - 教程
  • 多维索引技术优化数据湖查询性能
  • Umi-OCR_文字识别工具 免安装使用教程(附下载安装包)!永久免费,开源离线OCR识别软件下载
  • 【汇总】OPPO r9m 分区名、分区功能
  • 04_线程池实现
  • #D251010D. 未命名 10 (unnamed)
  • 【JAVA】从入门到放弃-01-HelloWorld - 指南
  • 离线应用程序
  • 2025表面瑕疵检测厂家TOP5推荐:表面瑕疵检测,薄膜瑕疵检测,瑕疵检测设备,瑕疵在线检测,铝箔瑕疵在线检测,外观瑕疵检测机,薄膜瑕疵检测仪,陶瓷膜瑕疵检测各种类型检测,精准高效的质量守护
  • 表格识别:不仅能识别文字,更能理解表格的结构和逻辑关系,实现输出可编辑、可分析的结构化数据