想过离线,但是好像不是很好做?
首先判定一个线段是否被另一个线段包含,这是好做的。
考虑按照右端点排序加入线段,以离散化的右端点为版本,以所属的集合为线段树内层下标,并用线段树维护区间集合左端点的最大值。
则一次查询相当于求 y 版本在 [l,r] 集合区间的最大左端点是否 ≥x,简单维护一下就好了。
#include <bits/stdc++.h>
#define PII pair<int, int>
using namespace std;
const int N = 6e5 + 15, INF = 0x3f3f3f3f;
int k, q, n;
struct node { int l, r, p; } a[N];
int b[N << 1], totb = 0;
vector<PII> v[N << 1];
int rt[N], tot = 0;
struct Tree { int ls, rs, Min; } tr[N << 6];
inline void pushup(int u) {
if (!tr[u].ls) tr[u].Min = tr[tr[u].rs].Min;
else if (!tr[u].rs) tr[u].Min = tr[tr[u].ls].Min;
else tr[u].Min = min(tr[tr[u].ls].Min, tr[tr[u].rs].Min);
}
void change(int &u, int l, int r, int x, int d) {
tr[++tot] = tr[u], u = tot;
if (l == r) return tr[u].Min = max(tr[u].Min, d), void();
int mid = l + r >> 1;
if (x <= mid) change(tr[u].ls, l, mid, x, d);
else change(tr[u].rs, mid + 1, r, x, d);
pushup(u);
}
int query(int u, int l, int r, int ql, int qr) {
if (!u || ql > qr) return INF;
if (l >= ql && r <= qr) return tr[u].Min;
int mid = l + r >> 1, res = INF;
if (ql <= mid) res = query(tr[u].ls, l, mid, ql, qr);
if (qr > mid) res = min(res, query(tr[u].rs, mid + 1, r, ql, qr) );
return res;
}
int main() {
scanf("%d%d%d", &k, &q, &n);
for (int i = 1; i <= n; i++) scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].p), b[++totb] = a[i].l, b[++totb] = a[i].r;
sort(b + 1, b + 1 + totb), totb = unique(b + 1, b + 1 + totb) - b - 1;
for (int i = 1; i <= n; i++) a[i].l = lower_bound(b + 1, b + 1 + totb, a[i].l) - b, a[i].r = lower_bound(b + 1, b + 1 + totb, a[i].r) - b;
for (int i = 1; i <= n; i++) v[a[i].r].push_back({a[i].l, a[i].p});
for (int i = 1; i <= k; i++) change(rt[0], 1, k, i, -INF);
for (int i = 1; i <= totb; i++) {
rt[i] = rt[i - 1];
for (PII j : v[i]) change(rt[i], 1, k, j.second, j.first);
}
while (q--) {
int l, r, x, y; scanf("%d%d%d%d", &l, &r, &x, &y);
x = lower_bound(b + 1, b + 1 + totb, x) - b, y = upper_bound(b + 1, b + 1 + totb, y) - b - 1;
if (query(rt[y], 1, k, l, r) >= x) puts("yes");
else puts("no");
cout.flush();
}
return 0;
}