[APIO2018] New Home 新家

题目链接

 

原文链接

-----> 稍微人话的翻译?

令位置$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('\n');
}

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; }

 

posted @ 2018-07-17 08:48  remoon  阅读(438)  评论(0编辑  收藏  举报