1 条题解
-
0
题目分析
本题要求实现两种操作:
区间加法:将区间 内的所有元素加上
区间查询:查询区间 内小于 的元素个数
数据规模为 ,直接暴力处理会超时,因此需要使用分块算法。
算法思路
分块思想 将数组分成 个块,每个块的大小约为 。对于每个块,我们维护:
原始数组 a[]
排序后的数组 b[](用于二分查找)
懒标记 lz[](记录整个块的增量)
关键操作
1.初始化建块 (build 函数) 计算块大小 和块数
为每个位置分配块编号 idx[i]
记录每个块的左右边界 L[i] 和 R[i]
对每个块内的元素进行排序,存入 b[] 数组
2.区间更新 (update 函数) 情况1:区间完全在一个块内
直接暴力更新 a[] 数组
重新构建该块的排序数组 b[]
情况2:区间跨越多个块
处理左不完整块:暴力更新并重新排序
处理中间完整块:只更新懒标记 lz[](不修改数组)
处理右不完整块:暴力更新并重新排序
- 区间查询 (query 函数) 情况1:区间完全在一个块内
暴力遍历,统计满足 a[i] + lz[sid] < k 的元素个数
情况2:区间跨越多个块
处理左不完整块:暴力统计
处理中间完整块:在排序数组 b[] 上二分查找满足条件的元素个数
处理右不完整块:暴力统计
时间复杂度
建块:
更新操作:
查询操作:
总体复杂度为 ,对于 可以接受。
代码实现要点
1.块的管理 ll B = sqrt(n), m = (n + B - 1) / B; for (ll i = 1; i <= n; i++) idx[i] = (i - 1) / B + 1; 2. 二分查找优化 在完整块中查询时,利用排序后的数组进行二分查找: ll LL = L[i], RR = R[i], pos = 0; while (LL <= RR) { ll mid = (LL + RR) >> 1; if (b[mid] + lz[i] < k) LL = mid + 1, pos = mid; else RR = mid - 1; } if (pos) ans += pos - L[i] + 1; 3.懒标记应用 更新完整块时只更新懒标记,查询时再将懒标记考虑进去: // 更新时 lz[i] += k;
// 查询时
a[i] + lz[sid] < k // 不完整块 b[mid] + lz[i] < k // 完整块二分代码总结
本题展示了分块算法的典型应用:
将大规模问题分解为小块处理
通过排序和二分优化查询
使用懒标记减少不必要的更新操作
分块算法在 复杂度级别的问题中非常实用,是介于暴力和高级数据结构之间的折中方案。
- 1
信息
- ID
- 3218
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者