You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组的范围更新与查询问题:寻求高效解决方案

最优解法:带懒标记的平衡树(在线O(q log n)复杂度)

暴力解法O(q*n)在q或者n规模较大时肯定扛不住,尤其是元素值能到1e18,显然不能用数组硬存状态。这里推荐用带区间懒标记的有序平衡树(比如Treap、Splay树)来处理,能把每次操作的时间复杂度降到O(log n),整体达到O(q log n)的最优在线复杂度。

核心思路

咱们把数组元素按值维护在一棵有序平衡树里,每个节点不仅存元素值,还维护子树的元素总数、当前值的重复计数,以及懒标记——用来批量处理“后缀减1”的操作(也就是操作1里所有>=x的元素减1)。

具体实现细节

平衡树节点结构

每个节点需要包含这些字段:

  • val:当前节点代表的元素值(需结合懒标记计算实际值)
  • count:该值对应的元素个数(比如有3个元素都是5,count就是3)
  • size:以当前节点为根的子树的总元素个数(用来快速统计排名)
  • lazy:子树所有元素需要减去的数值(懒标记,延迟更新子节点)
  • 左右孩子指针(平衡树的基础结构)

操作1:全局所有>=x的元素减1

这一步的关键是利用平衡树的有序性,所有>=x的元素是树的一个后缀子树:

  1. 在平衡树中找到第一个值>=x的节点,确定后缀子树的范围
  2. 给这个后缀子树的根节点加上懒标记-1(表示子树里所有元素的值都要减1)
  3. 注意懒标记的下传:当需要访问子节点时,必须先把当前节点的懒标记传递给左右孩子,更新孩子的val,然后清空当前节点的懒标记,保证后续操作的正确性

这样一来,整个操作只需要O(log n)的时间,不需要逐个修改元素。

操作2:查询[l, r]范围内的第x小元素

分两步走:

  1. 统计区间元素数量:先算出树中值小于l的元素总数cnt_l,再算出值小于等于r的元素总数cnt_r。如果x > cnt_r - cnt_l,说明没有足够的元素,按题目要求返回错误或特定值即可。
  2. 查找第k小元素:我们要找的是全局第cnt_l + x小的元素(因为前cnt_l个元素都小于l,第cnt_l + x个就是[l, r]里的第x小)。利用平衡树的size字段,可以快速定位这个元素:
    • 如果左子树的size >= k,说明目标在左子树,递归左孩子
    • 如果左子树size + 当前节点count >=k,说明目标就是当前节点的val(结合懒标记后的实际值)
    • 否则,递归右孩子,查找第k - (左子树size + 当前节点count)小的元素

为什么这个方法可行?

  • 解决了1e18数值的问题:平衡树是动态开点的,不需要预先分配内存,无论数值多大都能处理
  • 操作效率高:每次更新和查询都是O(log n),q次操作就是O(q log n),这是在线解法下的最优复杂度(因为每次操作至少需要log级别的时间来定位元素)
  • 懒标记避免了批量修改的开销:不需要逐个更新元素,而是用标记延迟处理,极大提升效率

替代方案(离线场景)

如果所有操作都是预先已知的(离线处理),可以用事件排序+前缀和的思路:

  1. 把所有操作1的x和查询的l、r都收集起来,和原始数组元素一起排序
  2. 用前缀和统计每个元素被操作1影响的次数,计算出当前值
  3. 再用排序后的数组配合二分查找处理查询,但这个方法只适用于离线场景,无法处理在线请求

内容的提问来源于stack exchange,提问作者Raghav James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:49:04