APIO 2018題解
阿新 • • 發佈:2020-09-02
【Problem 1】
Statemant:
Solution:
發現這題有時間和位置兩個維度,如果按位置排序似乎不太好做,於是考慮按時間排序。對於一個點,有效區間為\([a,b]\),可以把它拆成在\(a\)時間加人,在\(b+1\)時刻刪除。問題變成了如何快速找出最小的\(len\)使得\([p-len,p+len]\)中包含所有種類的點。按照區間數顏色的套路,每個點記錄一下往左走最先找到同顏色點的位置,為了方便,可以在最左邊每種顏色各放一個點。於是查詢一個區間的顏色轉化成查詢區間\([l,r]\)中有多少個點的資訊小於\(l\)。根據單調性可以二分這個區間長度。查詢顏色數的本質是二維數點,又因為二分強制線上,用資料結構維護複雜度應該不小於\(\log_2^2n\)
Code
#include <bits/stdc++.h> using namespace std; const int MAXN = 3.5E5; const int LIM = 2E8; int seg[MAXN*20]; int lc[MAXN*20]; int rc[MAXN*20]; int ans[MAXN]; multiset <int> prePos[MAXN*20]; multiset <int> S[MAXN]; struct Node { int tim; int pos; int opt; int kind; int id; Node() { tim = pos = opt = kind = id = 0; } Node(int _t, int _p, int _o, int _k, int _id) { tim = _t, pos = _p, opt = _o, kind = _k, id = _id; } inline friend bool operator < (Node a, Node b) { if (a.tim != b.tim) return a.tim < b.tim; return a.opt < b.opt; } } ; Node A[MAXN<<2]; int n, q, k, rt, totNode; int p, v, t, curNum; void upData(int& o, int l, int r) { if (!o) o = ++totNode; if (l == r) { if (t) prePos[o].insert(v); else prePos[o].erase(prePos[o].find(v)); seg[o] = (prePos[o].empty()) ? LIM : (*prePos[o].begin()); return ; } int mid = l + r >> 1; if (p <= mid) upData(lc[o], l, mid); else upData(rc[o], mid + 1, r); seg[o] = min(seg[lc[o]], seg[rc[o]]); } inline int getAns(int pos) { if (curNum < k) return -1; int l = 1; int r = LIM; int nowNode = rt; int nowMin = LIM; int tmpMin = LIM; int mid; while (l < r) { mid = l + r >> 1; tmpMin = min(nowMin, seg[rc[nowNode]]); if ((pos > mid) || (tmpMin < pos * 2 - mid)) l = mid + 1, nowNode = rc[nowNode]; else nowMin = tmpMin, r = mid, nowNode = lc[nowNode]; } return l - pos; } int main(void) { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> k >> q, seg[0] = LIM; for (int i = 1;i <= k; ++i) S[i].insert(-LIM), S[i].insert(LIM), p = LIM, v = -LIM, t = 1, upData(rt, 1, LIM); int m = 0; for (int i = 1;i <= n; ++i) { int a = 0, b = 0, c = 0, d = 0; cin >> a >> b >> c >> d; A[++m] = Node(c, a, 0, b, 0), A[++m] = Node(d + 1, a, 1, b, 0); } for (int i = 1;i <= q; ++i) { int a = 0, b = 0; cin >> a >> b; A[++m] = Node(b, a, 2, 0, i); } sort(A + 1, A + 1 + m); for (int i = 1;i <= m; ++i) { int o = A[i].opt; int pos = A[i].pos; int e = A[i].kind; if (o == 0) { int limL = *--S[e].lower_bound(pos); int limR = *S[e].lower_bound(pos); p = limR, v = pos, t = 1, upData(rt, 1, LIM); p = limR, v = limL, t = 0, upData(rt, 1, LIM); p = pos, v = limL, t = 1, upData(rt, 1, LIM); if (S[e].size() == 2) ++curNum; S[e].insert(pos); } else if (o == 1) { int limL = *--S[e].lower_bound(pos); int limR = *++S[e].lower_bound(pos); p = limR, v = pos, t = 0, upData(rt, 1, LIM); p = limR, v = limL, t = 1, upData(rt, 1, LIM); p = pos, v = limL, t = 0, upData(rt, 1, LIM); if (S[e].size() == 3) --curNum; S[e].erase(S[e].find(pos)); } else ans[A[i].id] = getAns(pos); } for (int i = 1;i <= q; ++i) cout << ans[i] << '\n'; return 0; }