区间集合管理 (Interval Management System)
针对频繁的区间合并与点查询,最理想的策略是维护一组不相交的连通区间(Disjoint Intervals)。
核心范式:基于有序集合的区间收缩
我们选择使用一个支持快速查找和维护有序性的数据结构(如 C++ 中的 std::set 或平衡树)来存储当前的连通块。每个块定义为一个三元组 ,其中:
: 区间左端点。
: 区间右端点。
: 该区间内的总水量(和)。
为什么选择此方案?
- 分摊复杂度分析:虽然单次合并操作
可能涉及多个现有区间的删除,但每个区间在整个生命周期中只会被创建一次、删除一次。因此,
次操作后的总删除次数上限为
。每次查找边界的复杂度为
,整体分摊复杂度为
。
- 空间高效:空间复杂度与区间数量成正比,最坏情况下为
。
- 查询直观:点查询
转化为在有序集合中定位包含
的区间
,其结果即为
。
代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct Pool {
int l;
int r;
mutable ll v;
bool operator<(const Pool& o) const {
return l < o.l;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
set<Pool> pool;
for (int i = 1; i <= n; i++) {
ll a;
cin >> a;
pool.insert({i, i, a});
}
while (m--) {
int op;
cin >> op;
if (op == 1) {
int ql, qr;
cin >> ql >> qr;
auto it = pool.lower_bound({ql, 0, 0});
if (it != pool.begin()) {
auto prev_it = prev(it);
if (prev_it->r >= ql) {
it = prev_it;
}
}
ll total = 0;
int nl = -1;
int nr = -1;
while (it != pool.end() && it->l <= qr) {
if (nl == -1)
nl = it->l;
nr = max(nr, it->r);
total += it->v;
it = pool.erase(it);
}
if (nl != -1) {
pool.insert({nl, nr, total});
}
} else if (op == 2) {
int pos;
cin >> pos;
auto it = pool.upper_bound({pos, 0, 0});
it = prev(it);
double ans = (double)it->v / (it->r - it->l + 1);
cout << fixed << setprecision(10) << ans << endl;
}
}
}
复杂度分析
| 维度 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 (合并) | 单次操作可能 |
|
| 时间复杂度 (查询) | 典型的二分查找复杂度。 | |
| 空间复杂度 | 存储区间三元组所需空间。 |

京公网安备 11010502036488号