【题目链接】
【思路要点】
- 对时间轴进行扫描线,在时间轴上的一段区间可以表示为一次插入操作和一次删除操作。
- 问题被转化为:维护一个序列,支持在某处插入/删除一个数,以及询问以某个位置为中心,包含所有种类的数的区间的最小长度。
- 对于询问,不难想到二分答案,二分答案后我们需要支持的是询问区间内是否出现了所有种类的数。
- 对于每一种数,我们维护一个支持查询前驱后继的平衡树(std::set)。
- 在序列上维护每个位置所有数中,该数上一次出现的位置,并取最小值作为这个位置的权值。
- 在序列末尾补上所有数各一个,当我们询问\([L,R]\)中是否存在所有数的时候,我们可以询问\([R+1,+\infty)\)内的权值最小值是否不小于\(L\)。
- 离散化商店的坐标,我们可以用线段树+堆来维护上述序列,其修改、查询的时间复杂度均为\(O(LogN)\)。
- 连上二分的复杂度,总时间复杂度\(O(NLogN+KLogN+QLog^2N)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 6e5 + 5; const int MAXV = 5e8 + 5; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } struct Heap { priority_queue <int, vector<int>, greater<int> > Heap, Delt; void push(int x) {Heap.push(x); } void delt(int x) {Delt.push(x); } int query() { while (!Delt.empty() && Heap.top() == Delt.top()) { Heap.pop(); Delt.pop(); } if (Heap.empty()) return MAXV; else return Heap.top(); } }; struct SegmentTree { struct Node { int lc, rc; int Min; } a[MAXN * 2]; Heap heap[MAXN]; int root, size, n; void build(int &root, int l, int r) { root = ++size; a[root].Min = MAXV; if (l == r) return; int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); } void init(int x) { n = x; root = size = 0; build(root, 1, n); } void update(int root) { a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min); } void insert(int root, int l, int r, int pos, int val) { if (l == r) { heap[l].push(val); a[root].Min = heap[l].query(); return; } int mid = (l + r) / 2; if (mid >= pos) insert(a[root].lc, l, mid, pos, val); else insert(a[root].rc, mid + 1, r, pos, val); update(root); } void insert(int x, int val) { insert(root, 1, n, x, val); } void delt(int root, int l, int r, int pos, int val) { if (l == r) { heap[l].delt(val); a[root].Min = heap[l].query(); return; } int mid = (l + r) / 2; if (mid >= pos) delt(a[root].lc, l, mid, pos, val); else delt(a[root].rc, mid + 1, r, pos, val); update(root); } void delt(int x, int val) { delt(root, 1, n, x, val); } int query(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].Min; int mid = (l + r) / 2, ans = MAXV; if (mid >= ql) chkmin(ans, query(a[root].lc, l, mid, ql, min(qr, mid))); if (mid + 1 <= qr) chkmin(ans, query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr)); return ans; } bool query(int ql, int qr) { return query(root, 1, n, qr + 1, n) >= ql; } } ST; struct changes {int x, y, t; bool ins; } c[MAXN]; struct querys {int x, y, home; } q[MAXN]; int n, tn, k, m, ans[MAXN]; int tot, cnt[MAXN], tpos[MAXN]; multiset <int> st[MAXN]; bool cmpc(changes a, changes b) {return a.y < b.y; } bool cmpq(querys a, querys b) {return a.y < b.y; } int low(int x) { return upper_bound(tpos + 1, tpos + tn + 1, x) - tpos - 1; } int up(int x) { return lower_bound(tpos + 1, tpos + tn + 1, x) - tpos; } void change(changes now) { multiset <int> :: iterator pos, tmp; int suc, pre; if (now.ins) { if (cnt[now.t]++ == 0) tot++; pos = st[now.t].insert(now.x); if (pos == st[now.t].begin()) pre = 0; else {tmp = pos; tmp--; pre = *tmp; } tmp = pos; tmp++; if (tmp == st[now.t].end()) suc = 0; else suc = *tmp; suc = low(suc); now.x = low(now.x); if (pre != 0) pre = low(pre); ST.delt(suc, pre); ST.insert(suc, now.x); ST.insert(now.x, pre); } else { if (--cnt[now.t] == 0) tot--; pos = st[now.t].lower_bound(now.x); if (pos == st[now.t].begin()) pre = 0; else {tmp = pos; tmp--; pre = *tmp; } tmp = pos; tmp++; if (tmp == st[now.t].end()) suc = 0; else suc = *tmp; st[now.t].erase(pos); suc = low(suc); now.x = low(now.x); if (pre != 0) pre = low(pre); ST.delt(suc, now.x); ST.delt(now.x, pre); ST.insert(suc, pre); } } int query(int x) { if (tot != k) return -1; int l = 0, r = 1e8; while (l < r) { int mid = (l + r) / 2; int ql = up(x - mid), qr = low(x + mid); if (ST.query(ql, qr)) r = mid; else l = mid + 1; } return l; } int main() { read(n), read(k), read(m); for (int i = 1; i <= n; i++) { int x, t, a, b; read(x), read(t), read(a), read(b); c[++tn] = (changes) {x, a, t, true}; c[++tn] = (changes) {x, b + 1, t, false}; } n = tn; for (int i = 1; i <= m; i++) read(q[i].x), read(q[i].y), q[i].home = i; sort(c + 1, c + n + 1, cmpc); sort(q + 1, q + m + 1, cmpq); tn = 0; for (int i = 1; i <= n; i++) tpos[++tn] = c[i].x; tpos[++tn] = MAXV; sort(tpos + 1, tpos + tn + 1); tn = unique(tpos + 1, tpos + tn + 1) - tpos - 1; ST.init(tn); for (int i = 1; i <= k; i++) { st[i].insert(MAXV); ST.insert(tn, 0); } int pos = 1; for (int i = 1; i <= m; i++) { while (pos <= n && c[pos].y <= q[i].y) change(c[pos++]); ans[q[i].home] = query(q[i].x); } for (int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0; }