Sum of Subarrays#12232

Sum of Subarrays (Editorial)

Written By : MathModel

We are asked to answer queries on an integer sequence a=(a_1,a_2,\dots,a_n). For each query (l_i,r_i) let L=l_i,\ R=r_i. We must compute:

\sum_{l=L}^{R}\ \sum_{r=l}^{R}\ \sum_{j=l}^{r} a_j

i.e. the sum of sums of all non-empty subarrays fully inside .

Claim #1 : For a fixed query , each element a_j contributes independently, by a count equal to the number of subarrays inside that contain position .

Proof : In the expression

\sum_{l=L}^{R}\sum_{r=l}^{R}\sum_{j=l}^{r} a_j,

the inner sum adds a_j exactly when lies inside the chosen subarray [l,r]. So we can swap the order of summation: instead of summing over subarrays first, we sum over positions , and count how many subarrays include . Thus the total equals

\sum_{j=L}^{R} a_j \cdot (\text{number of subarrays }[l,r]\subseteq[L,R]\text{ with } l\le j\le r).

Now we only need to count those subarrays for each .

A subarray [l,r] within contains iff

L\le l\le j \quad\text{and}\quad j\le r\le R.

So:

Therefore the number of subarrays containing is

(j-L+1)(R-j+1).

So the answer for query is:

\text{Ans}(L,R)=\sum_{j=L}^{R} a_j (j-L+1)(R-j+1).

Claim #2 : The weight (j-L+1)(R-j+1) can be expanded into a quadratic polynomial in .

Proof : Rewrite the weight as:

(j-L+1)(R-j+1)=(j-(L-1))((R+1)-j).

Expanding:

\begin{align*} (j-(L-1))((R+1)-j) &= j(R+1-j)-(L-1)(R+1-j)\\ &= j(R+1)-j^2-(L-1)(R+1)+(L-1)j\\ &= -j^2+(L+R)j+(R+1)(1-L). \end{align*}

Thus:

(j-L+1)(R-j+1)= -j^2+(L+R)j+(R+1)(1-L).

Substitute this back:

\begin{align*} \text{Ans}(L,R) &=\sum_{j=L}^R a_j\Big(-j^2+(L+R)j+(R+1)(1-L)\Big)\\[4pt] &= -\sum_{j=L}^R a_j j^2 \ +\ (L+R)\sum_{j=L}^R a_j j \ +\ (R+1)(1-L)\sum_{j=L}^R a_j. \end{align*}

So if we can answer the three segment sums

\sum a_j,\qquad \sum a_j j,\qquad \sum a_j j^2

in per query, we are done.

Define prefix sums (1-indexed):

They are precomputed in .

For a query let:

Then:

\text{Ans}(L,R)= -s_2+(L+R)s_1+(R+1)(1-L)s_0
n,q=map(int,input().split())
a=list(map(int,input().split()))

p=[0]*(n+1)
p2=[0]*(n+1)
p3=[0]*(n+1)

for i in range(n):
    p[i+1]=p[i]+a[i]
    p2[i+1]=p2[i]+a[i]*(i+1)
    p3[i+1]=p3[i]+a[i]*(i+1)*(i+1)

for _ in range(q):
    l,r=map(int,input().split())
    s0=p[r]-p[l-1]
    s1=p2[r]-p2[l-1]
    s2=p3[r]-p3[l-1]
    ans=-s2+(l+r)*s1+(r+1)*(1-l)*s0
    print(ans)

Complexity: \mathcal{O}(n+q)