Submission #1303131

#TimeUsernameProblemLanguageResultExecution timeMemory
1303131_callmelucianHarvest (JOI20_harvest)C++17
100 / 100
1998 ms262320 KiB
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;
using pl = pair<ll,ll>;
using pii = pair<int,int>;
using tpl = tuple<int,int,int>;

#define all(a) a.begin(), a.end()
#define filter(a) a.erase(unique(all(a)), a.end())

struct SparseBIT {
    map<ll,int> cached;
    ll limit;

    SparseBIT (ll limit) : limit(limit) {}
    ll p (ll k) { return k & -k; }

    void update (ll pos, int val) {
        for (; pos <= limit; pos += p(pos)) cached[pos] += val;
    }

    int preSum (ll pos) {
        int ans = 0;
        for (; pos; pos -= p(pos))
            ans += (cached.count(pos) ? cached[pos] : 0);
        return ans;
    }
    int query (ll L, ll R) { return preSum(R) - preSum(L - 1); }
};

const int mn = 4e5 + 5;
const ll MX = 2e14;
ll a[mn], b[mn], N, M, L, C;

namespace sunGraph {
    vector<pair<int,ll>> adj[mn], rev[mn], queries[mn], line;
    int num[mn], sz[mn], root, tail, timeDfs;
    ll weight[mn], result[mn], sumCycle, backEdge;
    vector<int> nodeList;
    bool vis[mn], process[mn], inCycle[mn];

    bool detectCycle (int u) {
        if (vis[u]) { // found cycle
            tie(root, backEdge) = line.back(), tail = u;
            int lastNode = 0;
            while (lastNode != u) {
                assert(line.size());
                lastNode = line.back().first;
                sumCycle += line.back().second;
                line.pop_back();
                inCycle[lastNode] = true;
            }
            return true;
        }
        vis[u] = true;
        for (auto [v, curWeight] : adj[u]) {
            line.emplace_back(u, curWeight);
            if (detectCycle(v)) return true;
            line.pop_back();
        }
        return false;
    }

    void dfsPrepare (int u) {
        process[u] = true, sz[u] = 1, num[u] = ++timeDfs;
        nodeList.push_back(u);
        for (auto [v, curWeight] : rev[u]) {
            if (process[v]) continue;
            weight[v] = weight[u] + curWeight;
            dfsPrepare(v);
            sz[u] += sz[v];
        }
    }

    void solveComponent (int u) {
        if (process[u]) return; // component that contains u is already processed
        line.clear();

        // preprocess graph
        if (!detectCycle(u)) {
            cout << "No cycle found" << endl;
            exit(0);
        }
        dfsPrepare(root);
        sort(all(nodeList), [&] (int a, int b) { return weight[a] < weight[b]; });
        int szComp = nodeList.size();

        // prepare queries
        vector<tuple<ll,int,int>> subtreeQuery; // type-1 query
        vector<pair<ll,int>> rootQuery; // type-2 query
        for (int u : nodeList) {
            for (auto [idx, T] : queries[u]) {
                if (!inCycle[u]) subtreeQuery.emplace_back(T + weight[u], u, idx);
                else if (u == root) rootQuery.emplace_back(T, idx);
                else { // general inCycle case
                    ll delay = weight[tail] - weight[u] + backEdge;
                    if (delay <= T) rootQuery.emplace_back(T - delay, idx);
                    subtreeQuery.emplace_back(T + weight[u], u, idx);
                }
            }
        }
        sort(all(subtreeQuery), greater<tuple<ll,int,int>>());
        sort(all(rootQuery), greater<pair<ll,int>>());

        // helper data structures and functions
        SparseBIT tree(szComp), modTree(MX);
        ll counter = 0, sumWeightDiv = 0;

        function<void(void)> subtreeProcess = [&]() {
            ll bound; int node, idx;
            tie(bound, node, idx) = subtreeQuery.back();
            subtreeQuery.pop_back();
            result[idx] += tree.query(num[node], num[node] + sz[node] - 1);
            // if (idx == 0) cout << "subtree " << idx << " " << node << " " << bound << " r" << tree.query(num[node], num[node] + sz[node] - 1) << endl;
        };

        function<void(void)> rootProcess = [&]() {
            ll T; int idx; tie(T, idx) = rootQuery.back();
            rootQuery.pop_back();
            result[idx] += (T / sumCycle + 1) * counter;
            result[idx] -= sumWeightDiv;
            result[idx] -= modTree.query(T % sumCycle + 1, MX);
            // if (idx == 0) cout << "root " << idx << " " << T << endl;
        };

        // sweep line
        for (int u : nodeList) {
            if (u <= N) continue;
            // process subtree queries
            while (subtreeQuery.size() && get<0>(subtreeQuery.back()) < weight[u]) subtreeProcess();
            // process root queries
            while (rootQuery.size() && rootQuery.back().first < weight[u]) rootProcess();

            // update node u
            counter++, sumWeightDiv += (weight[u] / sumCycle);
            tree.update(num[u], 1), modTree.update(weight[u] % sumCycle, 1);
        }
        
        // process remaining queries
        while (subtreeQuery.size()) subtreeProcess();
        while (rootQuery.size()) rootProcess();

        // reset data
        line.clear(), nodeList.clear();
        root = sumCycle = backEdge = timeDfs = 0;
    }

    void addEdge (int a, int b, ll weight) {
        adj[a].emplace_back(b, weight);
        rev[b].emplace_back(a, weight);
    }
};

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    // read input
    cin >> N >> M >> L >> C;
    for (int i = 1; i <= N; i++) cin >> a[i], a[i + N] = a[i] + L;
    for (int i = 1; i <= M; i++) cin >> b[i], b[i] += L;

    // graph edges
    ll CMod = C % L, CDiv = C / L;
    for (int i = N + 1; i <= 2 * N; i++) {
        int nextNode = upper_bound(a + 1, a + 2 * N + 1, a[i] - CMod) - a - 1;
        ll weight = CDiv * L + a[i] - a[nextNode];
        sunGraph::addEdge(i - N, nextNode - (nextNode > N ? N : 0), weight);
    }

    // virtual nodes' edges
    for (int i = 1; i <= M; i++) {
        int nextNode = upper_bound(a + 1, a + 2 * N + 1, b[i]) - a - 1;
        ll weight = b[i] - a[nextNode];
        sunGraph::addEdge(N + i, nextNode - (nextNode > N ? N : 0), weight);
    }

    // read queries
    int Q; cin >> Q;
    for (int i = 0; i < Q; i++) {
        int V; ll T; cin >> V >> T;
        sunGraph::queries[V].emplace_back(i, T);
    }

    // solve for each component and output answer
    for (int i = 1; i <= N; i++) sunGraph::solveComponent(i);
    for (int i = 0; i < Q; i++) cout << sunGraph::result[i] << "\n";

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