Prefix (2D and)

Posted by dserf on Tue, 15 Feb 2022 15:19:23 +0100

preface

The one-dimensional prefix sum is introduced earlier. The two-dimensional prefix sum is the online upgrade of the one-dimensional prefix sum. The one-dimensional prefix sum is reflected in the array, while the two-bit prefix sum is reflected in the matrix.

1, What are two-dimensional prefixes and?

Based on the one-dimensional prefix sum, what we seek now is the sum of the number of any submatrix in the matrix, so we can use the two-dimensional prefix sum to solve this problem.

2, 2D prefix and explanation

introduce

For a matrix
For example: define a matrix g[n][m]

const int n=3,m=4;
int g[n][m]={{1,5,6,8},{9,6,7,3},{5,3,2,4}};
g[n][m]
1   5   6   8
9   6   7   3
5   3   2   4
 (1) Find matrix(1,1)reach(2,2)And
 (2) Find matrix(0,1)reach(1,3)And

The easiest thing to think of is violent enumeration
Namely:
Question (1) 6 + 7 + 3 + 2 = 18
Question (2) 5 + 6 + 8 + 6 + 7 + 3 = 35
Its complexity is O(nm). If the matrix is short, it's OK, but when the data is too large, this method is somewhat time-consuming. Therefore, we introduce two-dimensional prefix and sum to reduce its complexity.

thinking

If we take this 3 * 4 matrix as a large rectangle
For problem (1), we can have another solution

< < let's live and see. I haven't understood the picture for the first time > >
(shadow is required)
The solution is: the shadow = large rectangle - (1) - (2) + (3);
Combined with g[n][m] matrix, we further analyze
Find the matrices g[1],g[2],g[3]

matrix g[1]                  
1   5   6   
9   6   7   
5   3   2   
matrix g[2]     matrix g[3]
1            1   5   6   
9 
5
problem(1)  It can be solved as follows: g[1]-g[2]-g[3]+1
 The question now is how to sum the matrices
 We introduce the two-dimensional prefix and sum[i][j]
sum[i][j]Is from(0,0)reach(i,j)Matrix sum of

That's a better solution
Question (1)=sum[3][3]-sum[2][0]-sum[0][2]+sum[0][0];
sum[n][m] can be obtained from g[n][m]

sum[n][m]
1   6   12   20
10  21  34   45
15  29  44   59

Question (1) = 44-15-12 + 1 = 18 = 6 + 7 + 3 + 2

Expand your thinking and broaden your horizons
 By the right question(1)The solution can be inferred
(set up sum[x1,y1][x2,y2]equivalent
 From( x1,y1)To( x2,y2)(and)
sum[x1,y1][x2,y2]
=sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]

The code implementation is as follows (example):

#include<bits/stdc++.h>
using namespace std;
const int n=3,m=4;
int g[n][m]={{1,5,6,8},{9,6,7,3},{5,3,2,4}};
int sum[n][m];
void pre_sum()   //Preprocessing generates two-dimensional prefixes and
{
	sum[0][0]=g[0][0]; //first
	for(int i=1;i<n;i++)
		sum[i][0]=sum[i-1][0]+g[i][0];  //First column
	for(int j=1;j<m;j++)
		sum[0][j]=sum[0][j-1]+g[0][j];  //first line
	for(int i=1;i<n;i++)
		for(int j=1;j<m;j++)
	sum[i][j]=g[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
}
int get_sum(int x1,int y1,int x2,int y2)
{
	if(!x1&&!y1)  return sum[x2][y2];
	if(!x1)    return sum[x2][y2]-sum[x2][y1-1];
	if(!y1)    return sum[x2][y2]-sum[x1-1][y2];
	return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}
int main()
{
	pre_sum();
	cout<<get_sum(1,1,2,2)<<""<<endl<<get_sum(0,1,1,3);
	return 0;
}

explain

Since sum [] [] is a two-dimensional array,
Therefore, the boundary should be specified first, and then the sum [] [] array should be preprocessed

void pre_sum()   //Preprocessing generates two-dimensional prefixes and
{
	sum[0][0]=g[0][0]; //first
	for(int i=1;i<n;i++)
		sum[i][0]=sum[i-1][0]+g[i][0];  //First column
	for(int j=1;j<m;j++)
		sum[0][j]=sum[0][j-1]+g[0][j];  //first line
	for(int i=1;i<n;i++)
		for(int j=1;j<m;j++)
	sum[i][j]=g[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
}

First of all, there must be no problem with the former sum[0][0]=g[0][0]
The following two for statements define the boundary of sum in advance

sum Specified boundary
1   6   12   20
10
15

The method of defining the boundary of two-dimensional prefix and is the same as that of one-dimensional prefix and
Then it is quite simple to find sum[i][j] according to the boundary

for(int i=1;i<n;i++)
	for(int j=1;j<m;j++)
		sum[i][j]=g[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];

Handle custom function get_ When sum(), return three special cases first
No matter how common the rule of return is, it's easy to understand. I won't say much (i.e. lazy)

summary

The two-dimensional prefix and the one-dimensional prefix are not difficult to understand. It may be easier to imagine a graph and use a graph to understand it.

Topics: C C++ Algorithm