一维前缀和数组

n个元素,m次询问
将时间复杂度简化到O(1)
sum[L,R]=sum[R]-sum[L-1] L>0
sum[L,R]=sum[R] L=0
O(n*j)
一维前缀和

#incldue<iostream>
using namespace std;

#define get_sum(L,R)(L?sum[R]-sum[L-1]:sum[R])
int get_sum(int L,int R){
	if(L!=0){
		return sum[R]-sum[L-1];
	}
	else return sum[R];
}
int main(){
const int n=5;
	int arr[n]={1,3,7,5,2};//原数组
	int sum[n];//前缀和数组
	sum[0]=arr[0];
	for(int i=1;i<n;i++)
	{
		sum[i]=sum[i-1]+arr[i];
	}
	for(int i=0;i<n;i++)
	cout<<sum[i]<<"  ";//输出一维前缀和数组
	
	cout<<get_sum(2,4)<<endl;
	cout<<get_sum(0,3)<<endl;
	cout<<get_sum(3,4)<<endl;
return 0;
}
//1 3  7  5  2
//1 4 11 16 18

一维差分

差分数组 和 前缀和数组 可以得到 原数组
O(n+m)

arr(原数组)13752
d(差分)124-2-3
sum(d)(前缀和)13752

差分标记:[L,R]+ V <=>d[L]+V ,d[R+1]-V

把标记后的 差分数组 进行 前缀和 操作
适用于多次操作单次(少次)询问

#include<iostream>
using namespace std;
int d[6]={0};
void add(int l,int r int v){
	d[l]+=v;
	d[r+1]-=v;
}
int  main(){
	int arr [5]={1,3,7,5,2};
	add(2,4,5);
	add(1,3,2);
	add(0,2,-3);
	for(int i=1;i<5;i++){
		d[i]+=d[i-1];
	}
	for(int i=0;i<5;i++){
		arr[i]+=d[i];
		cout<<arr[i]<<" ";
	}
	memset(d,0,sizeof(0));//如果查询多次可以初始化
return 0;
}

二维前缀和

定义:sum[i][j]是从[0,0]到[i,j]的和
O(1)求矩阵和

sum[x1,y1][x2,y2]= sum[x2][y2]  -sum[x2][y1-1] -  sum[x1-1][y2]  + sum[x1-1][y1-1]

sum[i][j]=g[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]

注:当出现i-1,j-1需要考虑数组越界
所以

当i=0,且j=0时 sum[0][0] =g[0][0]

当i=0,sum[0][i]=sum[0][i-1]+g[0][i]
sum{0,y1}{0,y2}=sum[0][y2]-sum[0][y1-1]

当j=0
sum[i][0]=sum[i-1][0]+g[i][0]
sum{x1,0}{x2,0}=sum[x2][0]-sum[x1-1][0]

或者在创建二维数组时,将数据从(1,1)开始写起,也就是同时将(0,i)为0,(j,0)为0,但是有时不允许

#include<iostream>
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(){
	sum[0][0]=g[0][0];//第一个
	for(int i=1;i<n;i++)sum[i][0]=sum[i-1][0]+g[i][0];//第一列
	for(int j=1;j<m;j++)sum[0][j]=sum[0][j-1]+g[0][j];//第一行
	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];//g为右下角
		}
	}
}
int get_sum(int x1,int y1,int x2,int y2){
	if(!x1&&!y1)return sum[x2][y2];//左上角为0,同定义
	if(!x1)return sum[x2][y2]-sum[x2][y1-1];//左上角的行为0,抽象为多行的一维前缀和
	if(!y1)return sum[x2][y2]-sum[x1-1][y2];//左上角的列为0,抽象为多列的一维前缀和
	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)<<" "<<get_sum(0,1,1,3);
	return 0;
}
//(1,1)到(2,2)的和 18
//(0,1)到(1,3)的和 35

arr

1568
9673
5324

sum

161220
10213445
15294459

二维差分

d[x1][y1]+=V,
d[x2+1][y1]-=V
d[x1][y2+1]-=V
d[x2+1][y2+1]+=V

arr

1568
9673
5324

(0,0)到(2,1)+3
(1,1)到(2,2)-1操作

drr

30-300
0-1010
00000
-313-10

sum前缀和

33000
32-100
32-100
00000

arr

4868
12863
8514
#include<iostream>
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];
int d[n+1][m+1];
void pre_sum(){
	sum[0][0]=g[0][0];//第一个
	for(int i=1;i<n;i++)sum[i][0]=sum[i-1][0]+d[i][0];//第一列
	for(int j=1;j<m;j++)sum[0][j]=sum[0][j-1]+d[0][j];//第一行
	for(int i=1;i<n;i++){
		for(int j=1;j<m;j++){
		sum[i][j]=d[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];//g为右下角
		}
	}
	
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			g[i][j]+=sum[i][j];
		}
	}
	memsert(d,0,sizeof d);
	memsert(sum,0,sizeof sum);
}


void add(int x1,int y1,int x2,int y2,int v){//矩阵修改
	d[x1][y1]+=v;
	d[x2-1][y1]-=v;
	d[x1][y2+1]-=v;
	d[x2+1][y2+1]+=v;
}
void print(){
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++)cout<<g[i][j]<<endl;
		cout<<endl;
	}
}
void printD(){
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++)cout<<d[i][j]<<endl;
		cout<<endl;
	}
} 

}
int main(){
	add(0,0,2,1,3);
	add(1,1,2,2,-1);
	pre_sum();
	print();
	return 0;
}//O(1)的操作
//O(n*n)的查询

更多推荐