大二进制数组三类范围操作需求:寻求支持RangeIntersectQuery的高效数据结构
解决方案:基于有序无重叠区间集合的实现
由于数组规模最大可达109,无法使用常规数组或线段树(内存占用过高),结合你的操作特征(`RangeSet`区间长度仅103),推荐使用有序、无重叠的区间集合维护所有被设置为1的区间(初始状态全为0,0的范围可通过1区间的补集推导),配合二分查找实现所有亚线性时间操作。
核心前提
维护的1区间集合始终满足:
- 区间按左端点升序排列
- 区间之间无重叠、无相邻(相邻区间会被合并为一个)
1. RangeSet(v, left, right) 实现
当v=1时(设置区间为1)
- 通过二分查找,快速定位所有与
[left, right)存在交集的1区间 - 删除这些重叠区间,将它们与
[left, right)合并为一个新的区间:[min(left, 所有重叠区间左端点), max(right, 所有重叠区间右端点)] - 将合并后的新区间插入集合,维持有序性
- 时间复杂度:
O(logN + K),其中N是当前1区间的数量,K是找到的重叠区间数(因RangeSet区间长度仅10^3,K不会过大)
当v=0时(设置区间为0)
- 通过二分查找,定位所有与
[left, right)重叠的1区间 - 对每个重叠区间
[a, b),拆分出可能的有效子区间:- 若
a < left,保留[a, left) - 若
b > right,保留[right, b)
- 若
- 删除原重叠区间,将拆分后的有效子区间插入集合
- 时间复杂度:
O(logN + K),K为重叠区间数
2. RangeIntersectQuery(left, right) 实现
- 通过二分查找,找到第一个左端点小于
right的1区间 - 遍历后续所有右端点大于
left的1区间,计算每个区间与[left, right)的交集:[max(a, left), min(b, right)) - 收集所有有效交集区间(满足左端点 < 右端点),返回结果列表
- 时间复杂度:
O(logN + M),M为结果区间的数量,远小于N
3. RangeQuery(left, right) 实现
检查区间是否全为1
- 验证
[left, right)是否被1区间完全覆盖:- 通过二分查找定位第一个左端点 ≤
left的1区间,确认其右端点 ≥left - 依次遍历后续区间,检查每个区间的左端点是否等于前一个区间的右端点,且最终覆盖到
right - 若所有覆盖区间的并集恰好等于
[left, right),返回true,否则返回false
- 通过二分查找定位第一个左端点 ≤
- 时间复杂度:
O(logN + K),K为覆盖所需的区间数
检查区间是否全为0
- 通过二分查找判断是否存在1区间与
[left, right)重叠:- 找到第一个左端点 >
left的区间,检查其左端点 <right - 同时检查前一个区间(若存在)的右端点 >
left - 若两种情况都不成立,说明无重叠,返回true;否则返回false
- 找到第一个左端点 >
- 时间复杂度:
O(logN)
实现细节
- 可以用语言自带的有序集合实现(如Python的
bisect模块维护有序列表,C++的std::set),快速完成二分查找、插入、删除操作 - 所有操作均为亚线性时间,完全满足你的性能要求
内容的提问来源于stack exchange,提问作者G.M
相关产品推荐
相关产品推荐

