1 条题解
-
0
问题分析
本题是一道基于树状数组(Fenwick Tree) 和离线处理的区间查询问题,核心任务是高效统计每个查询区间内满足特定条件的元素数量。具体来说,对于每个查询
[l, r, x],需要计算区间内“上升点”的数量(即前一个元素小于当前元素的位置),并考虑边界条件的特殊情况。算法思路
1. 数据预处理与离散化
- 离散化:将原始数组
a中的元素和所有查询的x值合并后排序去重,映射到[0, m-1]的范围(m为不同值的数量)。这一步的目的是减少数值范围,便于后续按值分组处理。 - 映射规则:使用
lower_bound将原始值转换为离散化后的索引,存储在a和x数组中。
2. 上升点标记(
tag数组)- 上升点定义:对于位置
i(i > 0),若a[i-1] < a[i],则i是一个上升点。 - 标记方式:对每个上升点
i,在tag数组中记录两个操作:- 向
tag[a[i-1]]中添加(i, 1):表示当处理值a[i-1]时,在位置i加1。 - 向
tag[a[i]]中添加(i, -1):表示当处理值a[i]时,在位置i减1。 这一设计用于后续按x筛选上升点。
- 向
3. 离线查询处理
- 查询排序:将所有查询按离散化后的
x值升序排序,便于按值顺序批量处理。 - 树状数组操作:
- 遍历离散化后的值
i,对每个值i先处理tag[i]中的所有标记(通过树状数组add函数更新位置的权重)。 - 处理所有
x值等于i的查询:- 用
rangeSum(l+1, r)计算区间[l+1, r]内的上升点数量(树状数组的区间和查询)。 - 若区间左端点
l的元素值大于x,则额外加1(边界条件修正)。
- 用
- 遍历离散化后的值
4. 结果输出
将处理后的查询结果按原始顺序输出。
关键公式与复杂度
-
离散化映射: 设原始值集合为
$$\text{idx}(x) = \text{lower\_bound}(v.begin(), v.end(), x) - v.begin() $$V,排序去重后得到v,则任意值x的离散化索引为:时间复杂度:
O((n + q) log(n + q))。 -
树状数组操作:
- 单点更新
add(x, y):O(log N),其中N为数组最大长度(1e6 + 1)。 - 区间查询
rangeSum(x, y):O(log N),通过前缀和差实现。
- 单点更新
-
总时间复杂度:
- 预处理与离散化:
O((n + q) log(n + q))。 - 标记处理与查询:
O(n log N + q log N + q log q)。 整体复杂度为O((n + q) log(n + q)),适合处理n, q ≤ 1e6的规模。
- 预处理与离散化:
代码解析
模块 功能描述 树状数组 add实现单点更新,sum实现前缀和查询,rangeSum计算区间和。离散化 合并数组元素与查询值,排序去重后映射为索引,减少数值范围。 上升点标记 对每个上升点 i,在tag中记录位置i的权重变化,用于后续筛选。离线查询 按 x排序查询,依次处理每个值对应的标记和查询,通过树状数组高效计算结果。算法的核心是通过离散化和离线处理,将分散的查询按值分组,结合树状数组的高效更新与查询能力,在大规模数据下快速统计满足条件的上升点数量,兼顾了时间效率和空间效率。
- 离散化:将原始数组
- 1
信息
- ID
- 3646
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者