Submission #1297758

#TimeUsernameProblemLanguageResultExecution timeMemory
1297758_callmelucianHarvest (JOI20_harvest)C++17
25 / 100
5093 ms79160 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())

const int mn = 4e5 + 5;
int a[mn], b[mn], n, m, C, L;

// this namespace solves the graph-related subproblem
namespace sunGraph {
    vector<pair<int,ll>> adj[mn], rev[mn];
    ll comp[mn], cycleID[mn], nxtWeight[mn], num[mn], sz[mn], root[mn], cycleLength[mn];
    ll treeDist[mn], preSum[mn], sumCycle[mn];
    bool inCycle[mn], vist[mn];

    void addEdge (int a, int b, ll weight) {
        // cout << a << " " << b << " " << weight << "\n";
        adj[a].emplace_back(b, weight);
        rev[b].emplace_back(a, weight);
    }
    
    ll detectCycle (int u) {
        static vector<pair<int,int>> line;
        static int counter = 0;

        if (vist[u]) { // found cycle
            vector<pair<int,int>> cycle;
            while (cycle.empty() || cycle.back().first != u)
                cycle.push_back(line.back()), line.pop_back();
            reverse(all(cycle));

            ll sumWeight = 0;
            for (auto [node, weight] : cycle) {
                cycleID[node] = ++counter, nxtWeight[counter] = weight;
                inCycle[node] = 1, cycleLength[counter] = cycle.size();
            }
            for (auto [node, weight] : cycle)
                nxtWeight[++counter] = weight, sumWeight += weight;
            line.clear();
            return sumWeight;
        }
        vist[u] = 1;
        for (auto [v, weight] : adj[u]) {
            line.emplace_back(u, weight);
            if (ll tmp = detectCycle(v)) return tmp;
            line.pop_back();
        }
        return 0;
    }

    void colorComponent (int u, int color) {
        if (comp[u]) return;
        comp[u] = color;
        for (auto [v, weight] : adj[u])
            if (!comp[v]) colorComponent(v, color);
        for (auto [v, weight] : rev[u])
            if (!comp[v]) colorComponent(v, color);
    }

    void dfsTree (int u, int r) {
        static int timeDfs = 0;
        num[u] = ++timeDfs, sz[u] = 1, root[u] = r;
        for (auto [v, weight] : rev[u]) {
            if (inCycle[v]) continue;
            treeDist[v] = treeDist[u] + weight;
            dfsTree(v, r);
            sz[u] += sz[v];
        }
    }

    void process() {
        // detect cycles and mark connected components
        int counter = 0;
        for (int i = 1; i <= n + m; i++) {
            // cout << "what!?" << endl;
            if (comp[i]) continue;
            sumCycle[++counter] = detectCycle(i);
            colorComponent(i, counter);
            // cout << "sc " << sumCycle[counter] << "\n";
        }

        // process trees
        for (int i = 1; i <= n; i++)
            if (inCycle[i]) dfsTree(i, i);
        
        // run prefix sums
        for (int i = 1; i <= 2 * n; i++)
            preSum[i] = preSum[i - 1] + nxtWeight[i];
    }

    // check if node c is in the subtree of st
    bool inTree (int st, int c) {
        return num[st] <= num[c] && num[c] < num[st] + sz[st];
    }

    // calculate the distance of going from a node with cycleID "from" to "to"
    ll goCycle (int from, int to) {
        if (from == to) return 0;
        if (from > to) to += cycleLength[to];
        return preSum[to - 1] - preSum[from - 1];
    }

    // the number of visiting time if we start from source, and want to reach the target
    ll visitTime (int source, int target, ll travelTime) {
        // cout << comp[source] << " " << comp[target] << " ";
        if (comp[source] != comp[target]) return 0;
        if (inCycle[target]) {
            ll length = treeDist[source] + goCycle(cycleID[root[source]], cycleID[target]);
            if (travelTime < length) return 0;
            return 1 + (travelTime - length) / sumCycle[comp[source]];
        }
        if (!inTree(target, source)) return 0;
        return travelTime >= treeDist[source] - treeDist[target];
    }
};

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

    // 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];

    // cout << "coordinate: ";
    // for (int i = 1; i <= 2 * n; i++) cout << a[i] << " ";
    // cout << "\n";


    // build edge
    int Cmod = C % L, Cdiv = C / L;
    for (int i = n + 1; i <= 2 * n; i++) {
        // cout << "searching " << a[i] - Cmod << "\n";
        int j = upper_bound(a + 1, a + 1 + 2 * n, a[i] - Cmod) - a - 1;
        int weight = C + (a[i] - Cmod - a[j]);
        sunGraph::addEdge(i - n, j - (j <= n ? 0 : n), weight);
    }

    // build virtual nodes for each apple tree
    for (int i = 1; i <= m; i++) {
        int j = upper_bound(a + 1, a + 1 + 2 * n, b[i] + L) - a - 1;
        sunGraph::addEdge(n + i, j - (j <= n ? 0 : n), b[i] + L - a[j]);
    }
    sunGraph::process();

    int q; cin >> q;
    while (q--) {
        // cout << "bro ";
        int V; ll T, ans = 0; cin >> V >> T;
        for (int i = 1; i <= m; i++)
            ans += sunGraph::visitTime(n + i, V, T);
        cout << ans << "\n";
    }

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