😎前缀和就是:
给定序列a[n],它的前缀和序列s[n]的s[i]=a[1]+..a[i]
前缀和序列的用处:解决多次询问区间[ i , j ]内a序列的和
区间求和时间复杂度o(1)
暴力区间求和时间复杂度o(N)
acwing795 一维前缀和
#include <bits/stdc++.h>//一维前缀和
using namespace std; const int N=100005;
int n,m,l,r;
int a[N],s[N];
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),s[i]=s[i-1]+a[i];//按定义构造前缀和序列s
while(m--){
scanf("%d%d",&l,&r);
cout<<s[r]-s[l-1]<<endl;//r及之前的减去l之前的为l~r
}
return 0;
} acwing796 二维前缀和 s[ i , j ]表示矩阵0,0至i,j的数和
#include <bits/stdc++.h>//二维前缀和
#define y1 yy //acwing全局不可用y1
using namespace std;
int n,m,q,x1,y1,x2,y2,c;
const int N=1004;
int a[N][N]={0},s[N][N]={0};
int main(int argc, char** argv) {
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&s[i][j]),
s[i][j]+=s[i][j-1]+s[i-1][j]-s[i-1][j-1];//定义构造s矩阵,此处涉及容斥定理(核心)
while(q--){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2,&c);
printf("%d\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);//是y1-1,x1-1,而不是x1,y1,是这个点的上一个数 (核心)
}//涉及容斥定理
return 0;
} 😎差分就是:给定序列a[n],差分序列(唯一的)b[n]满足a[i]=b[1]+..b[i],即前缀和的逆
差分序列的用处:解决多次在区间[ i , j ] 内所以数全部加上或减去一个数c,极少次(基本就最后一次求数组状态)求数组状态
差分区间连加时间复杂度o(2),求数组状态复杂度o(N);
和线段树及树状数组的区别:1.差分是多次对区间内所有数加减c,而树状数组是多次对某一个数加减c
2.差分是极少次求数组状态,而树状数组的频繁求数组状态
差分序列b 的构造可以看出原本a序列全部为0,每次读入a[ i ]就在区间[ i , i ]内插入a[ i ]
求原数组就按求前缀和序列的方法求
acwing797一维差分
#include <bits/stdc++.h>//一维差分
using namespace std;
const int N=100004;
int n,m,a[N],b[N],l,r,c;
void insert(int l,int r,int c){//在区间[l,r]内所有数+c(核心)
b[l]+=c; b[r+1]-=c;
}
int main(int argc, char** argv) {
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),insert(i,i,a[i]);//在区间【i,i】内所有数+a[i]的方式构造差分序列
while(m--){
scanf("%d%d%d",&l,&r,&c);
insert(l,r,c);//在区间[l,r]内所有数+c
}
for(int i=1;i<=n;i++) b[i]+=b[i-1],printf("%d ",b[i]);//用求前缀和的方法求出原数组(差分的前缀和)(核心)
printf("\n");
return 0;
} acwing798二维差分
对于a[ i , j ],矩阵b满足0,0到 i , j 的和等于a[ i,j ]
#include <bits/stdc++.h>
#define y1 yy
using namespace std;
int n,m,q,x1,y1,x2,y2,c;
const int N=1005;
int a[N][N],b[N][N];
void insert(int x1,int y1,int x2,int y2,int c){//在[x1,y1]到[x2,y2]内所有数加c,涉及容斥定理(核心)
b[x1][y1]+=c; b[x1][y2+1]-=c; b[x2+1][y1]-=c; b[x2+1][y2+1]+=c;
}
int main(int argc, char** argv) {
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),insert(i,j,i,j,a[i][j]);//在区间i,j到i,j内全部加a[i,]
while(q--){
scanf("%d%d%d%d%d",&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][j-1]+b[i-1][j]-b[i-1][j-1], printf("%d ",b[i][j]);//按求前缀和的方法求原数组(核心)
printf("\n");
}
return 0;
} 
京公网安备 11010502036488号