前缀和
对于数组
a1,a2,a3…an
前缀和
Si=a1+a2+…+an,S0=a0
对于
al,al+1,al+2…ar
可以用Sr-Sl-1表示
复杂度为O(1)
例题
#include <iostream>
using namespace std;
const int N=100010;
int main(){
int n,m,a[N],s[N];
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=0;i<m;i++){
int l,r;
cin>>l>>r;
cout<<s[r]-s[l-1]<<endl;
}
return 0;
}
拓展:子矩阵的和
例题:子矩阵的和
#include <iostream>
using namespace std;
const int N=1010;
int a[N][N],s[N][N];
int main(){
int n,m,q;
cin>>n>>m>>q;
int x1,y1,x2,y2;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
s[i][j]=a[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
for(int i=0;i<q;i++){
cin>>x1>>y1>>x2>>y2;
cout<<s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]<<endl;
}
return 0;
}
差分
差分是前缀和的逆运算
给定给S0,S1,S2…Sn
a1=S1
a2=S2-S1
a3=S3-S2
…
an=Sn-Sn-1
如果想让[l,r]上的每个S+c
则让al=al+lc,ar+1=ar+1-c
只需要O(1)的时间复杂度
例题:差分
#include <iostream>
using namespace std;
const int N=100010;
int main(){
int n,m,a[N],s[N];
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>s[i];
a[i]=s[i]-s[i-1];
}
for(int i=0;i<m;i++){
int l,r,c;
cin>>l>>r>>c;
a[l]+=c;
a[r+1]-=c;
}
for(int i=1;i<=n;i++){
s[i]=s[i-1]+a[i];
cout<<s[i]<<' ';
}
return 0;
}
例题:差分矩阵
#include <iostream>
using namespace std;
const int N=1010;
int a[N][N],s[N][N];
int main(){
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>s[i][j];
a[i][j]=s[i][j]-s[i-1][j]-s[i][j-1]+s[i-1][j-1];
}
}
for(int i=0;i<q;i++){
int x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
a[x1][y1]+=c;
a[x2+1][y1]-=c;
a[x1][y2+1]-=c;
a[x2+1][y2+1]+=c;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
cout<<s[i][j]<<" ";
}
cout<<endl;
}
return 0;
}