-----> 稍微人话的翻译?
令位置$i$的$pre$值为所有处在i位置(且开门)的商店的同种类型的前驱$x$的最小值
令$[i, inf)$中最小的$pre$值为 $mp(i)$
那么,对于$x$及$mid$,如果满足条件,一定有
$minpre [x + mid, inf) >= x - mid$
即 $mp(x + mid) >= x - mid$
令 $x + mid = i$
即有 $mp(i) >= -i + 2 * x$
因此有 $mp(i) + i >= 2 * x$
当求得$i ;get;max$时,$mid;get;max$
考虑如何二分
当 $mp(i) -> [mid + 1, r]$时,一定有 $i -> [mid + 1, r]$
而当 $mp(i) -> [l, mid]$时,$i$可能在$[l, mid]$,也可能在$[mid + 1, r]$
考虑如何判定在$[mid + 1, r]$中
由于$i + mp(i)$递减
因此,只需判断 $mid + 1$是否满足上述式子即可
因此,在二分的时候,同时需动态维护$mp(mid + 1)$
可以用线段树预先处理$min(pre(l),...pre(r))$,记作$mip[l, r]$
在二分的时候取$mip[mid + 1, r]$即可
二分往左时,注意$mp(mid + 1) = min(mip[a, b], mip[c, d], ...)$
因此注意取$min$即可
可以无视 -> (
考虑这么一种有趣的事情
如果我们化出了式子$i - mp(i) <= 2 * mid$
$mp(i) in [mid + 1, r]$时,有$i in[mid + 1, r]$
否则就类似上文的判断式子即可
对于$i - mp(i)$,我们需要快速的得到其的最大值
那么,线段树维护$i - mp(i) ;| ;i in[l,r]$的最大值
怎么维护呢?
当$mp(i)$变化时,尝试对其$i$前面所有的值进行更新。
这样做应该可行。。。。。。
出锅了跟我无关。。。。。。
)
复杂度 $O(n log n)$
细节挺多的
注意以下事情:
同一$t$,同一$x$可能有不同的商店
#include <cstdio> #include <set> #include <queue> #include <algorithm> #define sid 300050 #define ssd 10000005 #define inf 2e8 #define ri register int #define bst multiset <int> using namespace std; char RR[23345]; char WR[30000005], *Q = WR; #define pc(w) *Q ++ = w extern inline char gc() { static char *S = RR + 22000, *T = RR + 22000; if(S == T) fread(RR, 1, 22000, stdin), S = RR; return *S ++; } inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') { p = p * 10 + c - '0'; c = gc(); } return p * w; } int io[50], oi; inline void write(int x) { if(!x) pc('0'); if(x < 0) x = -x, pc('-'); while(x) io[++ oi] = x % 10, x /= 10; while(oi) pc(io[oi --] + '0'); pc(' '); } int n, k, q, rt, cnt, tot, gt, nc, tar[ssd]; int ans[sid], ls[ssd], rs[ssd], mip[ssd]; bst c[sid]; struct Control { int t, x, tp, id; friend bool operator < (Control a, Control b) { if(a.t != b.t) return a.t < b.t; return a.tp > b.tp; } } g[sid * 3]; struct Heap { priority_queue <int, vector<int>, greater<int> >q1, q2; int size() { return q1.size() - q2.size(); } bool empty() { return size() == 0; } void insert(int x) { q1.push(x); } void cancel(int x) { q2.push(x); } int top() { while(!q2.empty() && q1.top() == q2.top()) q1.pop(), q2.pop(); return q1.top(); } } h[sid]; void Modify(int &p, int l, int r, int mp, int v1, int v2) { if(!p) p = ++ cnt; if(l == r) { if(!tar[p]) tar[p] = ++ tot; Heap &T = h[tar[p]]; if(~v1) T.insert(v1); if(~v2) T.cancel(v2); mip[p] = T.empty() ? inf : T.top(); return; } int mid = (l + r) >> 1; if(mp <= mid) Modify(ls[p], l, mid, mp, v1, v2); else Modify(rs[p], mid + 1, r, mp, v1, v2); mip[p] = min(mip[ls[p]], mip[rs[p]]); } int Binary(int p, int l, int r, int mc, int qc) { if(l == r) return l - mc; int mid = (l + r) >> 1; int bc = min(qc, mip[rs[p]]); if(mc <= mid && bc + mid >= mc *2) return Binary(ls[p], l, mid, mc, bc); else return Binary(rs[p], mid + 1, r, mc, qc); } int main() { n = read(); k = read(); q = read(); mip[0] = inf; for(ri i = 1; i <= k; i ++){ c[i].insert(-inf); c[i].insert(inf); //放-inf的目的在于维护二分的正确性
//对于pre = 0的商店来说 //可以看做开始提前做了一次二分 //二分范围为-inf ~ inf //一开始是要取-inf,才能保证二分到 [0, inf]接着二分 Modify(rt, 0, inf, inf, -inf, -1); } for(ri i = 1; i <= n; i ++) { int x = read(), t = read(); int a = read(), b = read(); g[++ gt] = { a, x, 1, t }; g[++ gt] = { b, x, -1, t }; } for(ri i = 1; i <= q; i ++) { int l = read(), y = read(); g[++ gt] = { y, l, 0, i }; } sort(g + 1, g + gt + 1); for(ri i = 1; i <= gt; i ++) { int x = g[i].x, t = g[i].t; int id = g[i].id, tp = g[i].tp; if(tp == 1) { bst &p = c[id]; bst :: iterator cur = p.upper_bound(x), lst = cur --; swap(lst, cur); Modify(rt, 0, inf, *cur, x, *lst); Modify(rt, 0, inf, x, *lst, -1); if(p.size() == 2) nc ++; p.insert(x); } if(tp == 0) { if(nc == k) ans[id] = Binary(rt, 0, inf, x, inf); else ans[id] = -1; } if(tp == -1) { bst &p = c[id]; p.erase(p.find(x)); if(p.size() == 2) nc --; bst :: iterator cur = p.upper_bound(x), lst = cur --; swap(lst, cur); Modify(rt, 0, inf, *cur, *lst, x); Modify(rt, 0, inf, x, -1, *lst); } } for(ri i = 1; i <= q; i ++) write(ans[i]); fwrite(WR, 1, Q - WR, stdout); return 0; }