题目链接:包含每个查询的最小区间
题解:偏序+离线模板题,单点修改区间查询(我这里用的是树状数组)
1. 先把区间数组按左端点从小到大排序,询问数组也从小到大排序
2. 对于每一个询问k,先将所有左端点小于等于queries[k]的区间维护到树状数组上——以右端点为下标,区间长度为权值;再查询所有包含queries[k]的区间的最小长度,即区间查询树状数组[queries[k],MAXSIZE)的最小值。对于后续的询问,因为权值是递增的,所以之前所维护的区间的左端均小于询问的权值,重复上述操作即可
3. 如果不好理解,可以将区间和询问均想象成二维平面上的点,如下图所示:
low表示区间左端点,high表示区间右端点,high轴相当于我们所维护的树状数组
黑色的点表示维护的区间,红色点表示询问,对于2这个询问,我们只需要区间查询绿色框中所有区间的最小长度
4. 区间端点的值域太大,需要先进行离散化
代码示例:
class Solution {
public:
#define INF std::numeric_limits<int>::max()
vector<int> discrete;
vector<int> bitree, origin;
vector<pair<int, int>> que;
int n, m, sz;
int Idx(int x) {
return lower_bound(discrete.begin(), discrete.end(), x) - discrete.begin();
}
int Lowbit(int x) {
return x & -x;
}
void Modify(int x, int val) {
origin[x] = min(origin[x], val);
while (x < sz) {
bitree[x] = min(bitree[x], val);
x += Lowbit(x);
}
}
int Query(int l, int r) {
int res = INF;
while (r >= l) {
if (r - Lowbit(r) >= l) {
res = min(res, bitree[r]);
r -= Lowbit(r);
}
else {
res = min(res, origin[r]);
--r;
}
}
return res == INF ? -1 : res;
}
vector<int> minInterval(vector<vector<int>>& intervals, vector<int>& queries) {
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b)->bool { return a[0] < b[0]; });
n = intervals.size();
m = queries.size();
que.resize(m);
for (int i = 0; i < m; ++i) que[i] = pair<int, int>{ queries[i], i };
sort(que.begin(), que.end());
sz = n * 2 + m;
discrete.reserve(sz);
discrete.push_back(-1);
for (auto& i : intervals) {
discrete.push_back(i[0]);
discrete.push_back(i[1]);
}
for (auto i : queries) discrete.push_back(i);
sort(discrete.begin(), discrete.end());
discrete.erase(unique(discrete.begin(), discrete.end()), discrete.end());
sz = discrete.size();
bitree.resize(sz, INF);
origin.resize(sz, INF);
vector<int> res(m);
int i = 0, j = 0;
while (j < m) {
while (i < n && intervals[i][0] <= que[j].first) {
auto& pr = intervals[i];
Modify(Idx(pr[1]), pr[1] - pr[0] + 1);
++i;
}
res[que[j].second] = Query(Idx(que[j].first), sz - 1);
++j;
}
return res;
}
};