bzoj5462

线段树+set

按时间扫描线,对于每个位置维护当前位置商店的同类型商店的前继

每次查询二分答案,设当前位置为$p$,二分大小为$mid$,那么希望$[p-mid,p+mid]$覆盖了所有类型

等价于$(p+mid,inf)$之间所有商店的前继位置都大于等于$p-mid$

时间复杂度$O(nlog^2n)$

bzoj5462
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5, maxm = maxn * 28, inf = 1e9 + 5;
int n, k, q;
int ans[maxn];
namespace seg {
    multiset<int> s[maxn];
    int root, Pool, tot;
    int mn[maxm], lc[maxm], rc[maxm];
    map<int, int> id;
    void update(int l, int r, int &x, int pos, int val, int f) {
        if(!x) {
            x = ++Pool;
        }
        if(l == r) {
            if(id.find(l) == id.end()) {
                id[l] = ++tot;
            }
            int cur = id[l]; 
            if(f == -1) {
                s[cur].erase(s[cur].find(val));
            } else {
                s[cur].insert(val);
            }
            mn[x] = s[cur].size() ? *s[cur].begin() : 0x3f3f3f3f;
            return;
        }
        int mid = l + r >> 1;
        if(pos <= mid) {
            update(l, mid, lc[x], pos, val, f);
        } else {
            update(mid + 1, r, rc[x], pos, val, f);
        }
        mn[x] = min(mn[lc[x]], mn[rc[x]]);
    }
    int query(int l, int r, int x, int a, int b) {
        if(l > b || r < a || !x) {
            return inf;
        } 
        if(l >= a && r <= b) {
            return mn[x];
        }
        int mid = l + r >> 1;
        return min(query(l, mid, lc[x], a, b), query(mid + 1, r, rc[x], a, b));
    }
} 
struct data {
    int pos, type, t, f;
    data() = default;
    data(int _pos, int _type, int _t, int _f) : pos(_pos), type(_type), t(_t), f(_f) {}
    bool friend operator < (const data &a, const data &b) {
        return a.t == b.t ? a.f < b.f : a.t < b.t;
    }
};
multiset<int> s[maxn];
int main() {
    using seg::root;
    scanf("%d%d%d", &n, &k, &q);
    vector<data> events;
    for(int i = 1; i <= n; ++i) {
        int x, t, a, b;
        scanf("%d%d%d%d", &x, &t, &a, &b);
        events.push_back(data(x, t, a, 0));
        events.push_back(data(x, t, b + 1, -1));
    }
    for(int i = 1; i <= q; ++i) {
        int l, y; scanf("%d%d", &l, &y);
        events.push_back(data(l, i, y, 1));
    }
    memset(seg::mn, 0x3f3f, sizeof(seg::mn));
    sort(events.begin(), events.end());
    for(int i = 1; i <= k; ++i) {
        s[i].insert(inf);
        s[i].insert(-inf);
        seg::update(1, inf, root, inf, -inf, 1);
    }
    for(int i = 0; i < events.size(); ++i) {
        data tmp = events[i];
        if(tmp.f != 1) {
            int type = tmp.type, pos = tmp.pos, f = tmp.f;
            multiset<int> :: iterator it;
            if(f == 0) {
                it = s[type].lower_bound(pos);
                int tmp_p = *it;
                seg::update(1, inf, root, tmp_p, *(--it), -1);
                seg::update(1, inf, root, tmp_p, pos, 1);
                tmp_p = *it;
                it = s[type].insert(pos);
                seg::update(1, inf, root, pos, tmp_p, 1);
            } else {
                it = s[type].find(pos);
                int prev = *(--it);
                ++it;
                int next = *(++it);
                --it;
                seg::update(1, inf, root, pos, prev, -1);
                seg::update(1, inf, root, next, pos, -1);
                seg::update(1, inf, root, next, prev, 1);
                s[type].erase(it);
            }
        } else {
            int pos = tmp.pos, type = tmp.type;
            int l = -1, r = inf + 1, answer = -1;
            while(r - l > 1) {
                int mid = l + r >> 1;
                if(seg::query(1, inf, root, min(pos + mid + 1, inf), inf) >= pos - mid) {
                    r = answer = mid; 
                } else {
                    l = mid;
                }
            }
            ans[type] = answer;
        }
    }
    for(int i = 1; i <= q; ++i) {
        printf("%d\n", ans[i]);
    }
    return 0;
}
View Code

 

上一篇:PCL点云分割


下一篇:[总结]树链剖分的详细介绍