제출 #1332319

#제출 시각아이디문제언어결과실행 시간메모리
1332319MisterReaper수확 (JOI20_harvest)C++20
100 / 100
439 ms105252 KiB
#include <bits/stdc++.h>

using i64 = long long;

#ifdef DEBUG
    #include "debug.h"
#else
    #define debug(...) void(23)
#endif

std::mt19937 rng(23);

struct set {
    struct node {
        node* lc = nullptr;
        node* rc = nullptr;
        int wei = rng();
        int siz = 0;
        i64 x = 0;
        node() {}
        node(i64 x_) : siz(1), x(x_) {} 
    };

    node* root = nullptr;

    int size(node* v) { return v ? v->siz : 0; }
    void pull(node*& v) {
        if (!v) {
            return;
        }
        v->siz = size(v->lc) + size(v->rc) + 1;
    }

    void merge(node*& v, node* lv, node* rv) {
        if (!lv || !rv) {
            v = lv ? lv : rv;
            return;
        }
        if (lv->wei > rv->wei) {
            merge(lv->rc, lv->rc, rv);
            v = lv;
        } else {
            merge(rv->lc, lv, rv->lc);
            v = rv;
        }
        pull(v);
    }

    void split_by_x(node* v, node*& lv, node*& rv, i64 x) {
        if (!v) {
            lv = nullptr;
            rv = nullptr;
            return;
        }
        if (v->x <= x) {
            split_by_x(v->rc, v->rc, rv, x);
            lv = v;
        } else {
            split_by_x(v->lc, lv, v->lc, x);
            rv = v;
        }
        pull(lv);
        pull(rv);
    }

    void insert(i64 x) {
        node* a;
        node* b;
        node* nd = new node(x);
        split_by_x(root, a, b, x);
        merge(root, a, nd);
        merge(root, root, b);
    }

    int lower_bound(i64 x) {
        node* a;
        node* b;
        split_by_x(root, a, b, x);
        int res = size(a);
        merge(root, a, b);
        return res;
    }

    std::vector<i64> extract() {
        std::vector<i64> res;
        auto dfs = [&](auto&& self, node* v) -> void {
            if (!v) {
                return;
            }
            self(self, v->lc);
            res.emplace_back(v->x);
            self(self, v->rc);
        };
        dfs(dfs, root);
        return res;
    }

    void clear() {
        auto dfs = [&](auto&& self, node*& v) -> void {
            if (!v) {
                return;
            }
            self(self, v->lc);
            self(self, v->rc);
            free(v);
        };
        dfs(dfs, root);
    }

    int size() {
        return size(root);
    }

    void merger(node*& v, node* lv, node* rv) {
        if (!lv || !rv) {
            v = lv ? lv : rv;
            return;
        }
        if (lv->wei > rv->wei) {
            node* a;
            node* b;
            split_by_x(rv, a, b, lv->x);
            merger(lv->lc, lv->lc, a);
            merger(lv->rc, lv->rc, b);
            v = lv;
        } else {
            node* a;
            node* b;
            split_by_x(lv, a, b, rv->x);
            merger(rv->lc, a, rv->lc);
            merger(rv->rc, b, rv->rc);
            v = rv;
        }
        pull(v);
    }

    void merge_sets(const set& rhs) {
        merger(root, root, rhs.root);
    }
};

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int N, M;
    i64 L, C;
    std::cin >> N >> M >> L >> C;

    std::vector<i64> A(N), B(M);
    for (int i = 0; i < N; ++i) {
        std::cin >> A[i];
    }
    for (int i = 0; i < M; ++i) {
        std::cin >> B[i];
    }

    int Q;
    std::cin >> Q;

    std::vector<std::array<i64, 2>> qrys(Q);
    for (int i = 0; i < Q; ++i) {
        i64 V, T;
        std::cin >> V >> T;
        --V;
        qrys[i] = {V, T};
    }

    std::vector<int> f(N);
    std::vector<i64> dis(N);
    for (int i = 0; i < N; ++i) {
        i64 tim = (A[i] - C % L + L) % L;
        auto it = std::upper_bound(A.begin(), A.end(), tim);
        f[i] = (it == A.begin() ? N - 1 : int(it - A.begin() - 1));
        dis[i] = C + (it == A.begin() ? tim + L - A[N - 1] : tim - A[f[i]]);
    }

    debug(f);
    debug(dis);

    std::vector<int> on_cycle(N, true);
    std::vector<int> deg(N);
    for (int i = 0; i < N; ++i) {
        deg[f[i]] += 1;
    }

    std::queue<int> que;
    for (int i = 0; i < N; ++i) {
        if (deg[i] == 0) {
            que.emplace(i);
        }
    }

    std::vector<int> ord;

    while (!que.empty()) {
        auto v = que.front();
        que.pop();
        ord.emplace_back(v);
        on_cycle[v] = false;
        if (--deg[f[v]] == 0) {
            que.emplace(f[v]);
        }
    }

    debug(on_cycle);

    std::vector<i64> cycle_len(N, -1);
    std::vector<i64> cycle_loc(N, -1);
    std::vector<int> cycle_start(N, -1);
    for (int i = 0; i < N; ++i) {
        if (!on_cycle[i] || cycle_start[i] != -1) {
            continue;
        }
        i64 len = 0;
        int v = i;
        do {
            cycle_start[v] = i;
            cycle_loc[v] = len;
            len += dis[v];
            v = f[v];
        } while (v != i);
        cycle_len[v] = len;
    }

    debug(cycle_start);
    debug(cycle_loc);
    debug(cycle_len);

    std::vector<i64> need_fruit(M);
    std::vector<i64> start_fruit(M);
    for (int i = 0; i < M; ++i) {
        auto it = std::upper_bound(A.begin(), A.end(), B[i]);
        need_fruit[i] = (it == A.begin() ? N - 1 : int(it - A.begin() - 1));
        start_fruit[i] = (it == A.begin() ? B[i] + L - A[N - 1] : B[i] - A[need_fruit[i]]);
    }

    debug(need_fruit);
    debug(start_fruit);

    std::vector<std::vector<int>> have_fruit(N);
    for (int i = 0; i < M; ++i) {
        have_fruit[need_fruit[i]].emplace_back(i);
    }

    std::reverse(ord.begin(), ord.end());

    std::vector<int> cycle_enter(N, -1);
    std::vector<i64> cycle_enter_need(N, -1);
    for (auto i : ord) {
        if (on_cycle[f[i]]) {
            cycle_enter[i] = f[i];
            cycle_enter_need[i] = dis[i];
        } else {
            cycle_enter[i] = cycle_enter[f[i]];
            cycle_enter_need[i] = cycle_enter_need[f[i]] + dis[i];
        }
    }

    debug(cycle_enter);
    debug(cycle_enter_need);

    std::vector<i64> ans(Q);
    std::vector<std::vector<int>> ask(N);
    for (int i = 0; i < Q; ++i) {
        ask[qrys[i][0]].emplace_back(i);
    }

    std::vector<std::vector<int>> adj(N);
    for (int i = 0; i < N; ++i) {
        if (!on_cycle[i]) {
            adj[f[i]].emplace_back(i);
        } 
    }
    debug(__LINE__);

    std::vector<set> sets(N);
    auto dfs1 = [&](auto&& self, int v) -> void {
        for (auto u : adj[v]) {
            self(self, u);
            sets[v].merge_sets(sets[u]);
        }
        for (auto i : have_fruit[v]) {
            sets[v].insert(start_fruit[i] + cycle_enter_need[need_fruit[i]]);
        }
        debug(v, sets[v].extract());
        for (auto i : ask[v]) {
            auto t = qrys[i][1];
            ans[i] = sets[v].lower_bound(cycle_enter_need[v] + t);
        }
    };
    std::vector<std::vector<i64>> add_later(N);
    for (int i = 0; i < N; ++i) {
        if (!on_cycle[i] && on_cycle[f[i]]) {
            dfs1(dfs1, i);
            for (auto j : sets[i].extract()) {
                add_later[f[i]].emplace_back(j);
            }
            sets[i].clear();
        }
    }

    debug(__LINE__);

    adj.assign(N, {});
    for (int i = 0; i < N; ++i) {
        if (on_cycle[i] && i != cycle_start[i]) {
            adj[f[i]].emplace_back(i);
        }
    }

    auto dfs2 = [&](auto&& self, int v) -> void {
        debug(v);
        for (auto u : adj[v]) {
            self(self, u);
            sets[v].merge_sets(sets[u]);
        }
        if (v != cycle_start[v]) {
            for (auto i : have_fruit[v]) {
                sets[v].insert(cycle_len[cycle_start[v]] - cycle_loc[v] + start_fruit[i]);
            }
            for (auto i : add_later[v]) {
                sets[v].insert(cycle_len[cycle_start[v]] - cycle_loc[v] + i);
            }
        } else {
            for (auto i : have_fruit[v]) {
                sets[v].insert(start_fruit[i]);
            }
            for (auto i : add_later[v]) {
                sets[v].insert(i);
            }
        }
        if (v != cycle_start[v]) {
            for (auto i : ask[v]) {
                auto t = qrys[i][1];
                ans[i] += sets[v].lower_bound(cycle_len[cycle_start[v]] - cycle_loc[v] + t);
            }
        } 
    };
    for (int i = 0; i < N; ++i) {
        if (on_cycle[i] && i == cycle_start[i]) {
            dfs2(dfs2, i);
            std::vector<int> cyc;
            {
                int v = i;
                do {
                    cyc.emplace_back(v);
                    v = f[v];
                } while (v != i);
            }
            debug(i, sets[i].extract());
            auto vec = sets[i].extract();
            std::vector<std::array<i64, 2>> askall;
            for (auto v : cyc) {
                for (auto q : ask[v]) {
                    auto t = qrys[q][1] - cycle_loc[v];
                    askall.push_back({t, q});
                    // for (auto j : sets[i].extract()) {
                    //     if (j <= t) {
                    //         ans[q] += (t - j) / cycle_len[i] + 1;
                    //     }
                    // }
                }
            }
            i64 clen = cycle_len[i];
            std::sort(askall.begin(), askall.end());
            int p = 0;
            int cnt = 0;
            i64 sum = 0;
            set mset;
            for (auto[t, q] : askall) {
                while (p != int(vec.size()) && vec[p] <= t) {
                    cnt += 1;
                    sum += vec[p] / clen;
                    mset.insert(vec[p] % clen);
                    ++p;
                }
                ans[q] += (t / clen) * cnt - sum + mset.lower_bound(t % clen);
            }
        }
    }

    for (int i = 0; i < Q; ++i) {
        std::cout << ans[i] << '\n';
    }

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