Submission #1353034

#TimeUsernameProblemLanguageResultExecution timeMemory
1353034cnam9New Home (APIO18_new_home)C++20
10 / 100
1183 ms1114112 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#define inline inline __attribute__((always_inline))

using namespace std;

constexpr int N = 3e5 + 5;
constexpr int INF = 1e9;

struct Store {
    int x, type, l, r;
};

Store stores[N];
vector<int> positions[N];
int xoi[N];
int toi[N];

pair<int, int> queries[N];
vector<pair<int, int>> queries_at[N];

vector<int> lstores[N];
vector<int> rstores[N];

// sexagesicuaternary tree
class FastSet {
    using u64 = unsigned long long;
    int n;
    vector<vector<u64>> tree;

public:
    void assign(int n) {
        int sz = this->n = n;
        tree.clear();
        while (true) {
            int new_sz = (sz + 63) >> 6;
            tree.emplace_back(new_sz, ~0ull); // full set
            if (new_sz == 1) break;
            sz = new_sz;
        }

        if (n & 63 == 0) return;
        tree[0].back() &= (1ull << (n & 63)) - 1;
        int u = n >> 6;
        for (size_t h = 0; h < tree.size() - 1; h++) {
            if (tree[h][u]) break;

            int p = u >> 6;
            tree[h + 1][p] &= ~(1ull << (u & 63));
            u = p;
        }
    }

    void erase(int i) {
        if (i < 0 || i >= n) return;
        for (size_t h = 0; h < tree.size(); h++) {
            tree[h][i >> 6] &= ~(1ull << (i & 63));
            if (tree[h][i >> 6]) break;
            i >>= 6;
        }
    }

    // lower_bound
    int next(int i) const {
        if (i >= n) return n;

        for (size_t h = 0; h < tree.size(); h++) {
            int u = i >> 6;
            if (u >= tree[h].size()) break;
            
            u64 mask = tree[h][u] & (~0ull << (i & 63));
            if (!mask) {
                i = (i >> 6) + 1;
                continue;
            }
            i = (u << 6) + __builtin_ctzll(mask);
            for (int g = (int)h - 1; g >= 0; g--) {
                i = (i << 6) + __builtin_ctzll(tree[g][i]);
            }
            return (i < n) ? i : n;
        }
        return n;
    }

    // --upper_bound
    int prev(int i) const {
        for (size_t h = 0; h < tree.size(); h++) {
            int u = i >> 6;
            if (u < 0) break;
            
            u64 mask = tree[h][u];
            if ((i & 63) != 63) {
                mask &= (1ull << ((i & 63) + 1)) - 1;
            }
            
            if (!mask) {
                i = (i >> 6) - 1;
                continue;
            }
            i = (u << 6) + (63 - __builtin_clzll(mask));
            for (int g = (int)h - 1; g >= 0; g--) {
                i = (i << 6) + (63 - __builtin_clzll(tree[g][i]));
            }
            return i;
        }
        return -1;
    }

    inline bool operator[](int i) const {
        return (tree[0][i >> 6] >> (i & 63)) & 1;
    }

    inline size_t size() const {
        return n;
    }
};

FastSet fs[N];

struct SegmentTree {
    struct Node {
        int max;
        int lazy;

        inline void apply(int chmax) {
            max = std::max(max, chmax);
            lazy = std::max(lazy, chmax);
        }

        inline void push(Node &left, Node &right) {
            if (lazy == -INF) return;
            left.apply(lazy);
            right.apply(lazy);
            lazy = -INF;
        }

        inline void pull(const Node &left, const Node &right) {
            max = std::max(left.max, right.max);
        }
    } tree[4 * N];

    void update(int id, int l, int r, int u, int v, int chmax) {
        if (l >= v || r <= u) return;
        if (u <= l && r <= v) {
            tree[id].apply(chmax);
            return;
        }
        int m = l + r >> 1;
        tree[id].push(tree[id * 2], tree[id * 2 + 1]);
        update(id * 2, l, m, u, v, chmax);
        update(id * 2 + 1, m, r, u, v, chmax);
    }

    int query(int id, int l, int r, int u) {
        if (l + 1 == r) return tree[id].max;
        int m = l + r >> 1;
        tree[id].push(tree[id * 2], tree[id * 2 + 1]);
        if (u < m)
            return query(id * 2, l, m, u);
        return query(id * 2 + 1, m, r, u);
    }

    void build(int id, int l, int r) {
        tree[id].max = tree[id].lazy = -INF;
        if (l + 1 == r) {
            return;
        }
        int m = l + r >> 1;
        build(id * 2, l, m);
        build(id * 2 + 1, m, r);
    }
} Ltree, Rtree;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    // freopen("input.txt", "r", stdin);

    int n, k, q;
    cin >> n >> k >> q;

    for (int i = 0; i < n; i++) {
        auto &[x, type, l, r] = stores[i];
        cin >> x >> type >> l >> r;
    }
    sort(stores, stores + n, [](const Store &s, const Store &t) {
        return s.x < t.x;
    });
    for (int i = 0; i < n; i++) {
        positions[stores[i].type].push_back(i);
    }

    for (int i = 0; i < q; i++) {
        auto &[x, t] = queries[i];
        cin >> x >> t;

        xoi[i] = x;
        toi[i] = t;
    }

    sort(xoi, xoi + q);
    int X = unique(xoi, xoi + q) - xoi;

    sort(toi, toi + q);
    int T = unique(toi, toi + q) - toi;

    for (int i = 0; i < q; i++) {
        auto [x, t] = queries[i];
        x = lower_bound(xoi, xoi + X, x) - xoi;
        t = lower_bound(toi, toi + T, t) - toi;
        queries_at[t].emplace_back(x, i);
    }

    for (int i = 0; i < n; i++) {
        auto [x, type, l, r] = stores[i];
        l = lower_bound(toi, toi + T, l) - toi;
        r = upper_bound(toi, toi + T, r) - toi;

        lstores[l].push_back(i);
        rstores[r].push_back(i);
    }

    for (int type = 1; type <= k; type++) {
        for (int it = 0; it < positions[type].size(); it++) {
            int i = positions[type][it];
            stores[i].l = it;
        }
    }

    auto reset = [&]() {
        Ltree.build(1, 0, X);
        Rtree.build(1, 0, X);

        for (int type = 1; type <= k; type++) {
            fs[type].assign(positions[type].size());

            // cout << "f_" << type << "(x) = \\left\\{";

            int L = -INF;
            int Lmap = 0;
            for (int i : positions[type]) {
                int R = stores[i].x;
                int Rmap = lower_bound(xoi, xoi + X, R) - xoi;
                int Mmap = lower_bound(xoi, xoi + X, (L + R + 1) / 2) - xoi;

                // cout << L << " <= x < " << (L + R) * 0.5 << ": x - " << L << ", ";
                // cout << (L + R) * 0.5 << " <= x < " << R << ": " << R << " - x, ";
                Ltree.update(1, 0, X, Lmap, Mmap, -L);
                Rtree.update(1, 0, X, Mmap, Rmap, R);

                L = R;
                Lmap = Rmap;
            }
            // cout << L << " <= x: x - " << L << "\\right\\}" << endl;
            Ltree.update(1, 0, X, Lmap, X, -L);
        }
    };

    auto erase = [&](int type, int pos) {
        fs[type].erase(pos);

        int L = fs[type].prev(pos);
        int R = fs[type].next(pos);
        L = L < 0 ? -INF : stores[positions[type][L]].x;
        R = R >= fs[type].size() ? INF : stores[positions[type][R]].x;

        int Lmap = lower_bound(xoi, xoi + X, L) - xoi;
        int Mmap = lower_bound(xoi, xoi + X, (L + R + 1) / 2) - xoi;
        int Rmap = lower_bound(xoi, xoi + X, R) - xoi;

        // cout << "removed store type " << type << " at position " << x << ". Adjacent stores are " << L << " and " << R << endl;

        // cout << "y = \\left\\{";
        // cout << L << " <= x < " << (L + R) * 0.5 << ": x - " << L << ", ";
        // cout << (L + R) * 0.5 << " <= x < " << R << ": " << R << " - x\\right\\}" << endl;

        Ltree.update(1, 0, X, Lmap, Mmap, -L);
        Rtree.update(1, 0, X, Mmap, Rmap, R);
    };

    // L-R
    reset();
    // for (int Xmap = 0; Xmap < X; Xmap++) {
    //     int x = xoi[Xmap];
    //     cout << "f(" << x << ") = " << max(Ltree.query(1, 0, X, Xmap) + x,
    //                                        Rtree.query(1, 0, X, Xmap) - x) << endl;
    // }
    for (int t = 0; t < T; t++) {
        for (int i : rstores[t]) {
            auto [x, type, l, r] = stores[i];
            erase(type, l);
        }

        for (auto [Xmap, i] : queries_at[t]) {
            int x = xoi[Xmap];
            int &ans = queries[i].first;
            ans = max(Ltree.query(1, 0, X, Xmap) + x,
                      Rtree.query(1, 0, X, Xmap) - x);
        }
    }

    // R-L
    reset();
    for (int t = T - 1; t >= 0; t--) {
        for (int i : lstores[t + 1]) {
            auto [x, type, l, r] = stores[i];
            erase(type, l);
        }

        for (auto [Xmap, i] : queries_at[t]) {
            int x = xoi[Xmap];
            int &ans = queries[i].first;
            ans = max(ans,
                  max(Ltree.query(1, 0, X, Xmap) + x,
                      Rtree.query(1, 0, X, Xmap) - x));
        }
    }

    for (int i = 0; i < q; i++) {
        int ans = queries[i].first;
        cout << (ans > (int)1e8 ? -1 : ans) << '\n';
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...