Submission #1312443

#TimeUsernameProblemLanguageResultExecution timeMemory
1312443seriousgreySum Zero (RMI20_sumzero)C++20
22 / 100
74 ms22960 KiB
#pragma GCC optimize("O3,unroll-loops,no-stack-protector,fast-math")
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using vi = vector<int>;

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

    const int LOG = 20; // 2^20 = 1,048,576 > 4e5

    int n;
    if (!(cin >> n)) return 0;
    vi c(n);
    for (int i = 0; i < n; ++i) cin >> c[i];

    // Build prefix sums
    vector<ll> pref(n);
    for (int i = 0; i < n; ++i) {
        pref[i] = c[i] + (i ? pref[i-1] : 0LL);
    }

    // Coordinate-compress values: include 0 and all pref[i]
    vector<ll> vals;
    vals.reserve(n+1);
    vals.push_back(0LL);
    for (int i = 0; i < n; ++i) vals.push_back(pref[i]);
    sort(vals.begin(), vals.end());
    vals.erase(unique(vals.begin(), vals.end()), vals.end());
    int m = (int)vals.size();

    // positions for each compressed value
    vector<vector<int>> posList(m);
    // push -1 for prefix = 0
    int idx0 = int(lower_bound(vals.begin(), vals.end(), 0LL) - vals.begin());
    posList[idx0].push_back(-1);
    for (int i = 0; i < n; ++i) {
        int id = int(lower_bound(vals.begin(), vals.end(), pref[i]) - vals.begin());
        posList[id].push_back(i);
    }

    // nxt[i] = earliest j >= i with pref[j] == pref[i-1] (or n if none)
    vi nxt(n, n);
    for (int i = 0; i < n; ++i) {
        ll need = (i ? pref[i-1] : 0LL);
        int id = int(lower_bound(vals.begin(), vals.end(), need) - vals.begin());
        auto &v = posList[id];
        auto it = lower_bound(v.begin(), v.end(), i);
        nxt[i] = (it == v.end() ? n : *it);
    }

    // best[i] = minimal end among starts >= i
    vi best(n+1, n);
    for (int i = n-1; i >= 0; --i) best[i] = min(nxt[i], best[i+1]);

    // go[i] = position after taking that earliest-finishing interval (end+1), or n
    vi go(n+1, n);
    for (int i = 0; i < n; ++i) if (best[i] != n) go[i] = best[i] + 1;
    go[n] = n;

    // Binary lifting tables: pos[k][i] = position after applying 2^k greedy picks starting at i
    // cnt[k][i] = actual number of real segments represented by that 2^k-block
    vector<vi> pos(LOG, vi(n+1, n));
    vector<vi> cnt(LOG, vi(n+1, 0));

    for (int i = 0; i <= n; ++i) pos[0][i] = go[i];
    for (int i = 0; i < n; ++i) cnt[0][i] = (best[i] == n ? 0 : 1);
    cnt[0][n] = 0;

    for (int k = 1; k < LOG; ++k) {
        for (int i = 0; i <= n; ++i) {
            int mid = pos[k-1][i];
            pos[k][i] = (mid <= n ? pos[k-1][mid] : n);
            // cnt sums exact realized segments
            cnt[k][i] = cnt[k-1][i] + (mid <= n ? cnt[k-1][mid] : 0);
        }
    }

    int q; cin >> q;
    while (q--) {
        int l, r; cin >> l >> r;
        --l; --r;
        int p = l;
        int ans = 0;
        for (int k = LOG-1; k >= 0; --k) {
            if (p == n) break;
            int np = pos[k][p];
            // if this 2^k-block stays within range (end <= r) and actually contains segments
            if (np <= r + 1 && cnt[k][p] > 0) {
                ans += cnt[k][p];
                p = np;
            }
        }
        cout << ans << '\n';
    }

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