Submission #1316234

#TimeUsernameProblemLanguageResultExecution timeMemory
1316234sefatSum Zero (RMI20_sumzero)C++20
61 / 100
362 ms47080 KiB
#include <bits/stdc++.h> using namespace std; // Define long long for prefix sums as values can exceed 2^31 typedef long long ll; // Constraints: N <= 400,000. // We use 400,005 for safety. const int MAXN = 400005; const int LOGN = 20; // 2^19 > 400,000, so 20 is plenty safe. // Global arrays to prevent stack overflow int jump[LOGN][MAXN]; ll pr[MAXN]; int n, q; void solve() { if (!(cin >> n)) return; // Reading input and building prefix sums // pr[i] stores the sum of c[1]...c[i] pr[0] = 0; for(int i = 1; i <= n; ++i) { int val; cin >> val; pr[i] = pr[i-1] + val; } cin >> q; // 'mp' stores the LAST seen position of a prefix sum while iterating backwards. // Effectively, for current index 'i', it tells us the nearest 'j' >= i such that pr[j] == val. map<ll, int> mp; // Initialize the 'infinity' limit // If a subarray ends at 'n', the next one would start at 'n+1'. // So 'n+2' is a safe "infinity" / "no solution" marker. int INF = n + 2; // Initialize base cases for binary lifting beyond valid range for(int j = 0; j < LOGN; j++) { jump[j][n + 1] = INF; jump[j][n + 2] = INF; } // We keep track of the earliest ending position of a valid zero-sum subarray // found so far to the right. int min_end = INF; // Fill mp with the final prefix sum to handle cases where a subarray ends at N mp[pr[n]] = n; // Iterate backwards to build the first level of the jump table (jump[0]) // jump[0][i] = (end index of the nearest zero-sum subarray starting >= i) + 1 for(int i = n; i >= 1; --i) { // Check if there is a prefix sum P[j] == P[i-1] to the right // If yes, a zero-sum subarray exists from i to j. if (mp.count(pr[i-1])) { int segment_end = mp[pr[i-1]]; min_end = min(min_end, segment_end); } // jump[0][i] points to the start of the NEXT disjoint subarray. // If the best segment we found ends at 'min_end', the next one starts at 'min_end + 1'. jump[0][i] = min_end + 1; // Update map: current 'i' is now the leftmost occurrence of pr[i] seen so far // (but actually we need to store pr[i] for the future iterations i-1, i-2...) // effectively, mp[val] always stores the smallest index k >= current_i with pr[k] == val mp[pr[i-1]] = i - 1; // Correct logic is to store the index for P[i-1] check? // No, wait. For the NEXT iteration (i-1), we want to find P[(i-1)-1]. // The current iteration establishes P[i] is at index i. // Actually, the simple logic is: // We just processed index i. We want to make sure P[i-1] is available for future lookups of P[something] == P[i-1]. // But actually, we only need to update the map with the current prefix sum `pr[i-1]` // is NOT relevant for the right side matching. We need to add `pr[i-1]` as a potential END point for a subarray starting to the left? // No. // Let's re-verify map update logic: // A subarray starting at 'start' ends at 'end' if pr[end] == pr[start-1]. // When we are at 'i', we are the 'start'. We look for 'end' > 'i' such that pr[end] == pr[i-1]. // So we need the map to store positions of pr values to the RIGHT. // So at step 'i', we should add `pr[i-1]` to the map? No, `pr[i-1]` is the value BEFORE index i. // We are looking for a match to the right. The values to the right are `pr[i], pr[i+1]...`. // So we should have added `pr[i]` to the map in the PREVIOUS iteration (i+1). // Correct Loop Structure: // 1. Calculate best match for current 'i'. Match is found if `pr[i-1]` exists in map. // 2. Update `min_end`. // 3. Update map with `pr[i-1]`? No! `pr[i-1]` is a potential END point for a subarray starting at `i-something`. // But here we are moving left. // Ah, the map must store indices `k` where `pr[k]` exists. // At start of loop `i`, map contains indices `k > i`. // We check `pr[i-1]`. // Before going to `i-1`, we must add index `i-1` to the map? // No, index `i-1` is an END point for a subarray starting at `Left`. // So yes, we add `pr[i-1]` at index `i-1`. mp[pr[i-1]] = i - 1; } // Binary Lifting Construction // jump[j][i] is the starting position of the subarray after 2^j segments have been picked for(int j = 1; j < LOGN; ++j) { for(int i = 1; i <= n + 1; ++i) { int mid = jump[j-1][i]; if(mid > n + 1) jump[j][i] = INF; else jump[j][i] = jump[j-1][mid]; } } // Process Queries while(q--) { int l, r; cin >> l >> r; int ans = 0; int curr = l; for(int j = LOGN - 1; j >= 0; --j) { // We want to jump 2^j steps. // jump[j][curr] gives the START position of the (2^j + 1)-th segment. // If that start position is valid (meaning the 2^j-th segment ended <= r), we take it? // Wait, the definition: jump[j][curr] is the start of the next segment // AFTER consuming 2^j segments starting from curr. // So if jump[j][curr] - 1 <= r, it means all 2^j segments fit completely within [l, r]. if(jump[j][curr] <= r + 1) { // Why r+1? // jump[j][curr] is the start of the (2^j + 1)-th segment. // The previous segment ended at jump[j][curr] - 1. // We need that end <= r. // So jump[j][curr] - 1 <= r => jump[j][curr] <= r + 1. ans += (1 << j); curr = jump[j][curr]; } } cout << ans << "\n"; } } int main() { ios::sync_with_stdio(false); cin.tie(NULL); solve(); return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...