zoukankan      html  css  js  c++  java
  • [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('
    ');
    }
    
    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; }
  • 相关阅读:
    XP下在控制面板和登录界面中隐藏用户方法
    DataGirdView 单元格限制内容输入参考(按键时的判断)
    VB.Net操作Excel
    VS扩展:标签左置 — productivity power tools
    使用VBS自动删除已经从FTP下载下来的文件
    VB.Net下ComboBox操作收集
    修改网卡IP信息的批处理文件
    VB.NET自定义控件 —— 添加控件自定义属性
    使用关键字对数组进行模糊查找;对一维字符串数组进行排序
    mysql多字段模糊查询
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9321459.html
Copyright © 2011-2022 走看看