electicode
HomeCoursesResourcesProblemsNational OlympiadContestsLeaderboard
...
Problems/Arrays and Queries/Editorial

Editorial: Arrays and Queries

Notations & Definitions

Let's denote:

  • nnn = number of elements in array aaa
  • bbb = the final constructed array of size 2n−12^n - 12n−1
  • S(l,r)S(l, r)S(l,r) = sum of elements bl+bl+1+…+brb_l + b_{l+1} + \ldots + b_rbl​+bl+1​+
  • For any position ppp (1-indexed), we can represent it in binary
  • MOD=109+7\text{MOD} = 10^9 + 7MOD=109+7

Key Observation: The value at position ppp (1-indexed) in array bbb is determined by the position of the lowest set bit (trailing zeros) in ppp. Specifically, if position ppp has kkk trailing zeros in its binary representation, then bp=ak+1b_p = a_{k+1}b.

Subtask 1: All elements equal (ai=ca_i = cai​=c for all iii)

Editorial: When all elements are equal to some constant ccc, every position in array bbb has value ccc. Therefore:

S(l,r)=c⋅(r−l+1) mod MODS(l, r) = c \cdot (r - l + 1) \bmod \text{MOD}S(l,r)=c⋅(r−l+1)modMOD

Time Complexity: O(1)O(1)O(1) per query
Space Complexity: O(1)O(1)O(1)

Subtask 2: Queries where l=1,r=2k−1l = 1, r = 2^k - 1l=1,r=2k−1

Editorial: These queries ask for the sum of the entire array built after kkk rounds. We can use the recurrence:

  • After round 1: sum = a1a_1a1​
  • After round iii: sum = 2⋅sumi−1+ai2 \cdot \text{sum}_{i-1} + a_i2⋅sumi−1​+a

This is because b:=b+[ai]+bb := b + [a_i] + bb:=b+[ai​]+b, so the new sum is twice the old sum plus aia_iai​.

Time Complexity: O(n)O(n)O(n) per query
Space Complexity: O(1)O(1)O(1)

Subtask 3: n≤20n \leq 20n≤20

Editorial: For small nnn, we can actually construct the array bbb explicitly since ∣b∣=2n−1≤220−1≈106|b| = 2^n - 1 \leq 2^{20} - 1 \approx 10^6∣b∣=2n−1≤2. Then we can compute prefix sums and answer each query in .

Time Complexity: O(2n+q)O(2^n + q)O(2n+q)
Space Complexity: O(2n)O(2^n)O(2n)

Subtask 4: Point queries (l=rl = rl=r)

Editorial: For a point query at position ppp, we need to find which element of aaa is at position ppp. The key insight is that bp=ak+1b_p = a_{k+1}bp​=ak+ where is the number of trailing zeros in the binary representation of (equivalently, the position of the lowest set bit, 0-indexed from right).

Algorithm:

Example:

  • Position 1 (binary: 001): 0 trailing zeros → a1a_1a1​
  • Position 2 (binary: 010): 1 trailing zero → a2a_2a2​
  • Position 3 (binary: 011): 0 trailing zeros → a1a_1a1​
  • Position 4 (binary: 100): 2 trailing zeros →

Time Complexity: O(1)O(1)O(1) per query
Space Complexity: O(n)O(n)O(n)

Subtask 5: Full Solution

Editorial: The key insight is to compute prefix sums efficiently without building the array. For a position nnn (1-indexed), we can compute PrefixSum(n)\text{PrefixSum}(n)PrefixSum(n) by analyzing the binary representation of nnn.

Mathematical Insight: The contribution of each aia_iai​ to the prefix sum can be computed by examining the bits of nnn:

PrefixSum(n)=∑i=0k−1⌊n2i⌋⋅ai−⌊n2i⌋⋅ai−1\text{PrefixSum}(n) = \sum_{i=0}^{k-1} \left\lfloor \frac{n}{2^i} \right\rfloor \cdot a_i - \left\lfloor \frac{n}{2^i} \right\rfloor \cdot a_{i-1}PrefixSum(n)=∑i=0k−1​⌊

where a−1=0a_{-1} = 0a−1​=0.

The algorithm works as follows:

  1. Initialize ans=0\text{ans} = 0ans=0, prev=0\text{prev} = 0prev=0
  2. For each bit position iii from 0 to n−1n-1n−1 (while n>0n > 0n>):

To answer a query (l,r)(l, r)(l,r): compute PrefixSum(r)−PrefixSum(l−1)\text{PrefixSum}(r) - \text{PrefixSum}(l-1)PrefixSum(r)−PrefixSum(l−1).

Why this works: Each element aia_iai​ appears at positions where the number of trailing zeros equals iii. The number of such positions in the first nnn positions follows a pattern based on the binary representation of nnn. The term ⌊n/2i⌋\lfloor n/2^i \rfloor⌊n/2 counts occurrences, and subtracting the previous element's contribution accounts for the transition between levels.

Time Complexity: O(n)O(n)O(n) per query
Space Complexity: O(n)O(n)O(n)

← Back to Problem
…
+
br​
p
​
=
ak+1​
i​
20
−
1≈
106
O(1)O(1)O(1)
1
​
kkk
ppp
a3a_3
a3​
2i
n
​
⌋
⋅
ai​−
⌊2in​⌋⋅
ai−1​
0
  • Subtract the contribution of the previous element: ans−=n⋅prev\text{ans} -= n \cdot \text{prev}ans−=n⋅prev
  • Add the contribution of the current element: ans+=n⋅ai\text{ans} += n \cdot a_ians+=n⋅ai​
  • Update: prev=ai\text{prev} = a_iprev=ai​, n=⌊n/2⌋n = \lfloor n/2 \rfloorn=⌊n/2⌋
i
⌋
function getValue(p):
    k = __builtin_ctzll(p)  // count trailing zeros
    return a[k]
#include <bits/stdc++.h>
using namespace std;

const int64_t MOD = 1e9 + 7;
int64_t a[99], n;

int64_t mul(int64_t x, int64_t y) {
    x = (x % MOD + MOD) % MOD;
    y = (y % MOD + MOD) % MOD;
    return (x * y) % MOD;
}

int64_t add(int64_t x, int64_t y) {
    return (MOD + (x + y) % MOD) % MOD;
}

// Compute prefix sum for positions 1 to pos
int64_t prefixSum(int64_t pos) {
    int64_t ans = 0, prev = 0;
    for (int i = 0; i < n && pos > 0; i++) {
        ans = add(ans, mul(-pos, prev));
        ans = add(ans, mul(pos, a[i]));
        prev = a[i];
        pos /= 2;
    }
    return ans;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    
    int q;
    cin >> q;
    while (q--) {
        int64_t l, r;
        cin >> l >> r;
        cout << add(prefixSum(r), -prefixSum(l - 1)) << '\n';
    }
    
    return 0;
}