前言: 最近都在忙毕设和论文,已经好久没有写博客了。今天打周赛的时候遇到了区间合并的问题,前来记录一下。
区间合并算法
- 对于单次的区间合并,可以使用差分算法一次遍历即可,当区间范围在 [ 0 , 1 0 18 ] [0, 10^{18}] [0,1018] 的时间复杂度为 n l o g n nlogn nlogn
- 但是对于多区间问题,使用上述算法肯定会超时,因此这里来介绍一个 n l o g n nlogn nlogn 的区间合并与修改的算法模板。
/***
* @author : Laugh
* 适用范围 :
* 1. 用于管理形式为 [l, r) 的整数区间,区间无重叠
* 2. 加入 multiset<int> 可以实现 O(1) 获取最大长度
* 3. all 属性为所有区间的长度之和
*
*/
class RangeModule {
public:
int all;
// 不相交区间集合,存储形式为 [r, l)
set<pair<int, int>> rec;
RangeModule() {
all = 0;
}
// 插入区间 [L, R)
void insert(int L, int R) {
auto pos = rec.lower_bound({L, 0});
while(pos != rec.end()){
auto [r, l] = *pos;
if(l > R)
break;
all -= r - l;
L = min(L, l);
R = max(R, r);
rec.erase(pos++);
}
rec.emplace(R, L);
all += R - L;
}
// 判断是否包含某个区间
bool query(int L, int R) {
auto pos = rec.lower_bound({R, 0});
return pos != rec.end() and pos->second <= L;
}
// 删除区间 [L, R)
void remove(int L, int R) {
auto pos = rec.lower_bound({L + 1, 0});
vector<pair<int, int>> rest;
while(pos != rec.end()){
auto [r, l] = *pos;
if(l >= R)
break;
all -= r - l;
// 若不完全包含最左和最右区间,需要修改后插入
if(l + 1 <= L)
rest.emplace_back(L, l);
if(R < r)
rest.emplace_back(r, R);
rec.erase(pos++);
}
for(auto &[r, l] : rest){
rec.emplace(r, l);
all += r - l;
}
}
};