分块思想在算法中的工程化:平方分割与莫队算法的实现要诀

发布时间:2026/9/14 13:43:44

分块思想在算法中的工程化:平方分割与莫队算法的实现要诀 分块思想在算法中的工程化平方分割与莫队算法的实现要诀一、区间查询问题线段树不是唯一答案线段树是处理区间查询的经典数据结构单次查询 O(log n)功能强大。但它的实现代码量不小——建树、更新、查询三个递归函数一套下来至少几十行。而且不是所有场景都适合用线段树。如果数据是静态的不会在线更新或者查询的模式比较固定有没有比线段树更简单、更暴力但仍然够快的办法答案就是分块。分块思想的核心很简单把大规模数据按固定大小切成若干块预处理每块的聚合信息。查询时完整的块直接拿预计算的值零散的部分暴力计算。这样一次查询的复杂度在 O(sqrt(n)) 左右——比 O(log n) 慢一点但实现复杂度远低于线段树。在很多场景中O(sqrt(n)) 已经足够快。flowchart TD A[原始数组] -- B[按固定大小 sqrt#40n#41 分块] B -- C[块 0: 索引 0~B-1] B -- D[块 1: 索引 B~2B-1] B -- E[块 k: 索引 kB~n-1] C -- F[预计算块 0 的聚合值] D -- G[预计算块 1 的聚合值] E -- H[预计算块 k 的聚合值] I[区间查询 L, R] -- J{分析查询区间} J -- K[左边零散部分: 暴力遍历] J -- L[中间完整块: 直接用预计算值] J -- M[右边零散部分: 暴力遍历] K -- N[合并结果] L -- N M -- N二、平方分割最朴素的块最实用的效果平方分割是分块思想最基础的实现。假设数组长度为 n每块大小取 sqrt(n) 左右。为什么要取 sqrt(n)因为一次查询最多涉及 sqrt(n) 个完整块每块 O(1) 拿聚合值和两端各 sqrt(n) 个零散元素暴力计算——总复杂度 O(sqrt(n))。如果块大小取得太大零散部分变多如果块大小取得太小完整块变多。sqrt(n) 恰好在这两者之间取得最优平衡。以区间求和为例。每块预存块内元素的和。查询区间 [L, R] 时对于 L 所在的块中从 L 到块尾的部分逐个累加。对于 L 和 R 之间的完整块取出预计算的和O(1) 搞定。对于 R 所在的块中从块头到 R 的部分逐个累加。更新操作同样简单修改元素值后更新该元素所在块的聚合值。整个实现不超过 40 行代码。三、莫队算法把分块用在查询重排上分块不仅能优化数据结构还能优化查询的执行顺序。莫队算法就是这样一个技巧当有大量离线区间查询不需要在线返回、允许批量处理后一并输出时通过调整查询的执行顺序让指针移动的总次数从 O(mn) 降到 O(nsqrt(m))。莫队算法的核心操作是把所有查询按左端点所在块号排序同块内的按右端点排序。排序后维护两个指针 L 和 R表示当前处理到的区间。处理下一个查询时通过移动 L 和 R 来覆盖目标区间。因为排序后的查询顺序让指针的移动距离大大缩短总体复杂度从平方降到了 n*sqrt(m)。/** * 莫队算法离线区间查询优化 * * 适用条件 * 1. 查询是离线的不需要立刻回答 * 2. add/remove 操作是 O(1) 的可逆操作 * 3. 查询之间相互独立 * * 复杂度O(n * sqrt(m))n 是数组长度m 是查询数量 */ public class MoAlgorithm { // 块大小n / sqrt(m)使总复杂度最优 private int blockSize; /** * 处理所有区间查询 * * param arr 原始数组 * param queries 所有查询 [l, r, index] * return 按原始顺序排列的查询结果 */ public int[] processQueries(int[] arr, int[][] queries) { int n arr.length; int m queries.length; // 块大小理论最优值为 n / sqrt(m) // 这里用 n / Math.sqrt(m) 是为了让指针移动次数最少 blockSize (int) (n / Math.sqrt(m)); if (blockSize 0) blockSize 1; // 第一步将查询按莫队排序规则排列 // 规则1左端点所在块号小的排前面 // 规则2同块内按右端点排序奇数块升序、偶数块降序进一步优化 Query[] qs new Query[m]; for (int i 0; i m; i) { qs[i] new Query(queries[i][0], queries[i][1], i); } Arrays.sort(qs, (a, b) - { int blockA a.l / blockSize; int blockB b.l / blockSize; if (blockA ! blockB) { return blockA - blockB; } // 奇偶块排序优化减少 R 指针的无谓移动 return (blockA % 2 0) ? a.r - b.r : b.r - a.r; }); // 第二步从头开始处理所有查询维护 [curL, curR] 区间 int curL 0, curR -1; int curSum 0; // 当前区间的聚合值以求和为例 int[] results new int[m]; for (Query q : qs) { // 扩展右边界包含更多元素 while (curR q.r) { curR; curSum arr[curR]; // add 操作O(1) } // 收缩右边界排除多余元素 while (curR q.r) { curSum - arr[curR]; // remove 操作O(1) curR--; } // 扩展左边界包含更多左侧元素左边界左移 while (curL q.l) { curL--; curSum arr[curL]; // add 操作O(1) } // 收缩左边界排除多余左侧元素左边界右移 while (curL q.l) { curSum - arr[curL]; // remove 操作O(1) curL; } // 四个 while 的顺序很重要 // 先扩后缩可以避免指针交叉导致的数组越界 results[q.index] curSum; } return results; } /** * 查询内部类 */ private static class Query { int l, r; // 查询区间 [l, r] int index; // 原始顺序用于恢复输出顺序 Query(int l, int r, int index) { this.l l; this.r r; this.index index; } } }四个 while 循环的顺序不是随意排列的。基本原则是先扩展再收缩避免指针位置非法。如果先收缩左边界while (curL q.l) curL在 curR 还没扩展到位的情况下curL 可能越过 curR造成 sum 减去了不该减的元素。正确的顺序是先扩展右边界和左边界再收缩右边界和左边界。四、分块方法的适用场景与限制分块思想的优势在于实现简单和适用面广。不像线段树需要预定义区间操作的类型和、最大值、最小值分块对区间操作的类型几乎没有限制——只要块的聚合能快速更新就行。而且分块天然支持单点更新这一点比前缀和要灵活。但它的劣势也同样明确在线查询时 O(sqrt(n)) 比 O(log n) 慢n 达到 10^6 时差距就明显了。莫队只适用于离线查询需要拿到全部查询后才能重排。分块的常数因子不小块大小、排序策略都会影响实际效率需要针对具体数据做调优。分块和线段树不是替代关系而是互补关系。复杂动态区间操作如区间乘加混合更新用线段树简单静态或偶有更新的数据用分块。选择的依据是实现的复杂度 VS 查询的复杂度哪个在你的场景里权重更高。五、总结分块思想用暴力 预处理的组合在 O(sqrt(n)) 的复杂度下解决了区间查询问题。平方分割是最基础的分块应用莫队算法则把分块引入查询重排领域大幅减少离线批量查询中指针移动的总次数。分块的魅力不在于复杂度和实现有多精致而在于思路的直白——把大的拆成小的整块的巧算零散的死算。这种简单但有效的套路在实际工程中比精巧但脆弱的数据结构更值得信赖。
延伸阅读

更多相关文章

2026/9/15 2:07:58

AI 工具的用户反馈闭环:从隐性信号到模型优化

AI 工具的用户反馈闭环:从隐性信号到模型优化 一、用户反馈不只是「好评」和「差评」 独立产品的用户反馈,传统形式是评分(1-5星)或评论。对于 AI 工具,这些显式反馈(用户主动给出的评价)有价值,但其覆盖率通常不到 1%——绝大多数用户不会主动评价。如果只依赖显…

2026/9/10 15:45:51

AI 任务的优先级调度:不同用户、不同任务的资源分配

AI 任务的优先级调度:不同用户、不同任务的资源分配 一、当 AI 调用开始排队 产品在成长期,AI 调用量不再是「即来即处理」。在高并发时刻(如工作时间、产品推广期),AI API 的请求可能会出现排队——用户的请求发出了,但需要等待前面的请求处理完才能轮到。 如果所有…

2026/9/12 20:56:29

【AI问数】大模型选型与微调:AI问数的LLM落地实战

4 大选型维度 多模型 路由策略 99.97% 可用性 Spider 权威Benchmark AI问数对LLM的选型要求:中文理解强、SQL生成能力突出(Spider/Bird跑分)、上下文窗口足够(16K)、支持私有化部署。鲲溟KM AI采用多模型路由:主模型专用模型备用模型三层配置。 一…

2026/9/15 2:06:23

算力落地实践:从云平台选型到本地推理的避坑指南

邬贺铨院士那句“2030年中国算力有望占到全球30%”,乍一听是个宏观判断,但真往细里想,背后全是产业机会和落地问题。算力这个词最近几年被反复提起,从AI大模型训练到日常用的智能应用,本质上都是算力在支撑。做开发和搞…

2026/9/15 2:06:23

从QSignalMapper到lambda:Qt信号处理的现代化演进

1. QSignalMapper的兴衰与lambda的崛起在Qt框架的发展历程中,QSignalMapper曾经是信号处理的重要工具类。我第一次接触这个类是在2010年开发一个多媒体控制面板时,当时需要处理十几个按钮的点击事件,每个按钮需要触发相同的槽函数但携带不同的…

2026/9/15 2:06:23

QoS度量标准与服务模型全解析:从带宽时延到超图GPA模型

干网络这行的人,十有八九都听过QoS,但真被问一句“你打算怎么量化服务质量”,不少人还是会卡住。带宽、时延、抖动、丢包这些词谁都能说两句,可一到选服务模型、定SLA、做验收的时候就含糊了。这篇东西我打算从QoS度量标准讲起&am…

2026/9/15 2:06:23

微PE工具箱实战指南:从U盘启动盘制作到Win10重装与故障排查

1. 开工前的认知:微PE工具箱到底是什么,能解决什么问题第一次接触微PE的人,多半是被“重装系统”“U盘启动盘”这些词带进来的。我最早用微PE,是为了给一台老笔记本换固态硬盘后重装Win10,当时手头没有系统光盘&#x…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码