(一)前缀和
前缀和是一个思想,模板很简单。
一维前缀和
原数组: a0=0 a1 a2 a3 a4……an
前缀和数组:s0=0 s1 s2 s3 s4……sn
下标从1开始,并且定义s0=0是为了处理边界例如[1,x],并且保证求[l,r]公式s[r]-s[l-1]统一
- 如何求si
for(i=1;i<=n;i++) s[i]=s[i-1]+ai;
- 前缀和的作用:
求任意[l,r]的和
AcWing795:
- 代码
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll a[N],n,m,s[N];
int main(){
ios::sync_with_stdio(false);//使输入输出同步加快cin、cout的速度
//但是要注意加了这个就不能使用scanf,printf
cin.tie(0);cout.tie(0);
cin>>n>>m;
a[0]=0,s[0]=0;//处理边界
//下标从1开始用于处理边界,例如求[1,x];并且求[l,r]能统一公式s[r]-s[l-1]。
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
while(m--){
ll l,r;
cin>>l>>r;
cout<<s[r]-s[l-1]<<endl;
}
return 0;
}
二维前缀和同理:
AcWing796:
代码:
#include<iostream>
using namespace std;
typedef long long ll;
int main(){
ll n,m,q;
scanf("%ld %ld %ld",&n,&m,&q);
ll a[1005][1005];
ll s[1005][1005];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%ld",&a[i][j]);
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]-s[i-1][j-1]+a[i][j];//前缀和
while(q--){
ll x1,y1,x2,y2;
scanf("%ld %ld %ld %ld",&x1,&y1,&x2,&y2);
cout<<s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]<<endl;//局部和
}
return 0;
}
(二)差分
差分其实是前缀和的逆运算
一维差分
原数组: a1 a2 a3……an
构造: b1 b2 b3……bn
使得ai=b1+b2+…+bi
所以b1=a1,b2=a2-a1……bn=an-a(n-1)
即b为a的差分,a是b的前缀和
AcWing797
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
ll n,m,a[N],b[N];
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
b[1]=a[1];
for(int i=2;i<=n;i++) b[i]=a[i]-a[i-1];
while(m--){
ll l,r,c;
cin>>l>>r>>c;
b[l]+=c;
b[r+1]-=c;
}
for(int i=1;i<=n;i++) b[i]+=b[i-1];
for(int i=1;i<=n;i++) cout<<b[i]<<" ";
cout<<endl;
return 0;
}
二维差分同理:
AcWing798
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005;
ll n,m,q;
ll a[N][N],b[N][N];
void insert(ll x1,ll y1,ll x2,ll y2,ll c){
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) insert(i,j,i,j,a[i][j]);
while(q--){
ll x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
insert(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) cout<<b[i][j]<<" ";
cout<<endl;
}
return 0;
}