题意
有 n 个线段集合,一共有 k 个线段。m 次查询,每次查询是否对于 [a,b] 内所有集合,都至少有一个线段 [x,y] 满足 l≤x≤y≤r。强制在线。
分析
首先,如果可以离线,我们就考虑枚举 r,然后依次把 x=r 的线段加入,问题就是是否对于所有的集合 [a,b] 满足存在 a≥l。我们只需要知道每个集合的最大 a 值,然后查询区间最小值。
现在有了强制在线,我们直接套主席树即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define N 200005
#define K 600005
il ll rd(){
ll s = 0, w = 1;
char ch = getchar();
for (;ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1;
for (;ch >= '0' && ch <= '9'; ch = getchar()) s = ((s << 1) + (s << 3) + ch - '0');
return s * w;
}
int n, m, k, kl[K], kr[K], kp[K], nls[K << 1], cnt, rt[K << 1], mx[N], a, b, x, y;
vector <int> pos[K << 1];
int tr[N << 6], ls[N << 6], rs[N << 6], ep;
il int lsh(int x){return lower_bound(nls + 1, nls + cnt + 1, x) - nls;}
void add(int &p, int t, int l, int r, int x, int k){
p = ++ep, tr[p] = tr[t], ls[p] = ls[t], rs[p] = rs[t];
if (l == r) return tr[p] = k, void(0);
int mid = (l + r) >> 1;
if (x <= mid) add(ls[p], ls[t], l, mid, x, k);
else add(rs[p], rs[t], mid + 1, r, x, k);
tr[p] = min(tr[ls[p]], tr[rs[p]]);
}
int ask(int p, int l, int r, int nl, int nr){
if (nl <= l && r <= nr) return tr[p];
int mid = (l + r) >> 1, ans = 1e9;
if (nl <= mid) ans = min(ans, ask(ls[p], l, mid, nl, nr));
if (nr > mid) ans = min(ans, ask(rs[p], mid + 1, r, nl, nr));
return ans;
}
int main(){
n = rd(), m = rd(), k = rd();
for (int i = 1; i <= k; i++) kl[i] = rd(), kr[i] = rd(), kp[i] = rd(), nls[++cnt] = kl[i], nls[++cnt] = kr[i];
sort (nls + 1, nls + cnt + 1);
cnt = unique(nls + 1, nls + cnt + 1) - nls - 1;
for (int i = 1; i <= k; i++) kl[i] = lsh(kl[i]), kr[i] = lsh(kr[i]), pos[kr[i]].push_back(i);
for (int i = 1; i <= cnt; i++){
rt[i] = rt[i - 1];
for (int t : pos[i]) mx[kp[t]] = max(mx[kp[t]], kl[t]), add(rt[i], rt[i], 1, n, kp[t], mx[kp[t]]);
}
while (m--){
a = rd(), b = rd(), x = rd(), y = rd();
x = lower_bound(nls + 1, nls + cnt + 1, x) - nls, y = upper_bound(nls + 1, nls + cnt + 1, y) - nls - 1;
int mt = ask(rt[y], 1, n, a, b);
puts(mt >= x ? "yes" : "no");
cout.flush();
}
return 0;
}