Codeforces Round 1133 (Div. 1, Div. 2) is coming soon! Register here. ×

An Interesting Approach to Sum of Maximums in a Table

Revision en2, by Sersp3, 2026-08-22 14:06:44

I couldn't find this particular approach in existing editorials, so I decided to share it.

1. Problem

You are given a 2D table $$$a$$$ with $$$n$$$ rows and $$$m$$$ columns. You need to answer $$$q$$$ queries offline. Each query is four integers $$$x_1$$$ $$$y_1$$$ $$$x_2$$$ $$$y_2$$$ describing a rectangle. For each query, you need to output

$$$\sum_{i=x_1}^{x_2} (\max_{j=y_1}^{y_2} a_{i, j})$$$

2. How to Approach the Solution

If we calculate the maximum for each row separately for every query, we get $$$O(qmn)$$$. We can build a Sparse Table for each row and find each maximum in $$$O(1)$$$. This reduces the total complexity to $$$O(mn\log(m) + qn)$$$. However, we can do better.

3. Removing Maximums from the Query

Let's create new table $$$b$$$ with $$$n$$$ rows and $$$m$$$ columns.

$$$ b_{i,j}= \begin{cases} \max_{k=0}^{j}(a_{i,k}) - \max_{k=0}^{j-1}(a_{i,k}), & j \ne 0, a_{i,j}, & j = 0. \end{cases} $$$

Now, if a query has $$$y_1 = 0$$$, its answer is simply

$$$ \sum_{i=x_1}^{x_2} \sum_{j=0}^{y_2} b_{i, j} $$$

Indeed, because

$$$ \forall i \in [0,n-1],\quad \sum_{j=0}^{y} b_{i,j} = \max_{k=0}^{y} a_{i,k}. $$$

4. Moving the Left Border

The main problem now is updating $$$b_{i, j}$$$ when we move the left border from $$$y_1$$$ to $$$y_1+1$$$. Let's consider one row separately and assume $$$y_1 = 0$$$, as the other cases are similar. Now, let $$$a$$$ be a one-dimensional array.

$$$ b_i = \begin{cases} a_i, & i = 0,\\ \max\limits_{k=0}^{i} a_k - \max\limits_{k=0}^{i-1} a_k, & i \gt 0. \end{cases} $$$
$$$ c_i = \begin{cases} 0, & i \lt 1,\\ a_i, & i = 1,\\ \max\limits_{k=1}^{i} a_k - \max\limits_{k=1}^{i-1} a_k, & i \gt 1. \end{cases} $$$

The key observation is that b and c differ only in a small number of positions. Let's define a one-dimensional array $$$right$$$, where $$$right_i$$$ is the index of the nearest element to the right that is greater than $$$a_i$$$. We can calculate the $$$right$$$ array using a monotonic stack. Let's consider two cases: $$$x_1 \ge x_0$$$ and $$$x_1 \lt x_0$$$ The first case is easy. If $$$x_1 \ge x_0$$$, we only need to change two values in $$$b$$$:

$$$ b_0 \leftarrow 0,\qquad b_1 \leftarrow x_1. $$$

The second case is harder. If $$$x_1 \lt x_0$$$

$$$ b_1 \leftarrow 0, $$$
$$$ b_{right_i} \leftarrow a_{right_i} - a_i, \qquad i = 1,\ right_1,\ right_{right_1},\ldots $$$

while

$$$ a_i \lt a_0. $$$

Indeed, after removing $$$a_0$$$, the prefix maximum remains equal to $$$a_i$$$ until we reach the first element greater than $$$a_i$$$. Therefore, for every element $$$a_i \lt a_0$$$ on this chain, its next greater element $$$a_{right_i}$$$ becomes the position where the prefix maximum increases, so its new contribution is $$$a_{right_i} - a_i$$$.

Once we reach an element $$$a_i \gt a_0$$$, all further values of $$$b$$$ remain unchanged, since $$$a_0$$$ was not the maximum anymore.

Thus, we can update the representation for the new left border by following the chain of nearest greater elements.

7. Processing the Queries

We can now process all queries offline by sorting them by their left border $$$y_1$$$.

Initially, we set $$$y_1=0$$$.

and construct the corresponding array $$$b$$$. Then we process the queries in increasing order of $$$y_1$$$. Whenever we move the current left border from $$$y_1$$$ to $$$y_1+1$$$, we apply the updates described in the previous section to every row.

After the current left border becomes equal to the left border of the query, the answer can be obtained as

$$$ \sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y_2} b_{i,j}. $$$

Therefore, we need a data structure that supports point updates of $$$b_{i,j}$$$ and rectangle sum queries.

We can use a two-dimensional Fenwick tree for this purpose. Every change of one value of $$$b$$$ is performed as a point update, while the answer to a query is obtained using four prefix sums.

Thus, after sorting the queries by $$$y_1$$$, we maintain the correct representation of the prefix maximums for the current left border and answer every query independently.

8. Complexity of Updating b

The only remaining question is how many changes we perform when moving the left border.

Consider one row. When the left border is moved from $$$y_1$$$ to $$$y_1+1$$$, we follow the chain of nearest greater elements

$$$ i=y_1+1,\quad i=right_{i},\quad i=right_{i},\ldots $$$

while

$$$ a_i \lt a_{y_1}. $$$

So we need to take the contribution of these chains into account when analyzing the complexity. Let's prove that the intersection of every pair of chains is empty. This will give us a total complexity of $$$O(m)$$$.

Let $$$i$$$ and $$$j$$$ be the starting points of two chains, and assume that $$$i \lt j$$$. Suppose, for contradiction, that $$$k$$$ is a common element of the two chains.

Since $$$k$$$ belongs to the chain starting at $$$i$$$, we have $$$a_i \lt a_k$$$.

On the other hand, since $$$k$$$ belongs to the chain starting at $$$j$$$, it means that $$$a_{j-1} \gt a_k$$$.

But since $$$i \lt j$$$, the element $$$a_k$$$ is a maximum of the segment $$$[i,k]$$$, which contains $$$a_{j-1}$$$. Therefore, $$$a_k \ge a_{j-1}$$$ which contradicts $$$a_{j-1} \gt a_k$$$.

Since all elements of the chains are indices in the range $$$[0,m-1]$$$, and the chains are pairwise disjoint, the total number of updated indices in $$$b$$$ is $$$O(m)$$$.

9. Complexity

Let's analyze the complexity.

For every row, moving the left border requires following a chain of nearest greater elements. Each element can be processed only when it is reached by this procedure, so the total number of such updates over the whole process is linear in the number of elements of the row.

As shown in Section 8, the total number of updates $$$b$$$ is

$$$ O(nm). $$$

Using a two-dimensional Fenwick tree, each point update and each prefix-sum query takes

$$$ O(\log n\log m). $$$

Hence, maintaining $$$b$$$ takes

$$$ O(nm\log n\log m). $$$

Each rectangle query requires four prefix sums, so all $$$q$$$ queries take

$$$ O(q\log n\log m). $$$

The total complexity is therefore

$$$ \boxed{ O((nm+q)\log n\log m) }. $$$

The memory complexity is

$$$ \boxed{O(nm)}. $$$

10 Usage.

This problem

Tags data structures, 2d fenwick tree, offline queries, amortized analysis, algorithms

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en6 English Sersp3 2026-08-22 19:54:00 132
en5 English Sersp3 2026-08-22 17:41:25 276
en4 English Sersp3 2026-08-22 14:29:59 401 (published)
en3 English Sersp3 2026-08-22 14:10:15 251
en2 English Sersp3 2026-08-22 14:06:44 3746
en1 English Sersp3 2026-08-22 11:35:34 2478 Initial revision (saved to drafts)