前缀和差分主要用于在一段范围内的数组中进行加减操作
在数组a[n]中,其前缀和数组s[n]
s[n]=s[n-1]+a[n]
特别注意!!!s[0]一定要空出来,s[n]初始化一定要从1开始,防止数组越界
例:求n个数中在[l,r]中的和
const int N = 1000010;
int a[N];
int s[N];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + a[i]; //构造s[n]数组
int r, l;
cin >> l >> r;
cout << s[r] - s[l-1]; //再求某范围的和时,左边的范围要-1
return 0;
}
二维前缀和
s[n][m]为长为n,宽为m的矩阵全部加起来的数
s[n][m]-s[n-1][m]-s[n][m-1]+s[n-1][m-1]=a[n][m]
注意防止数组越界问题!!!!!
const int N = 10010;
int a[N][N];
int s[N][N];
int main()
{
int n, m;
cin >> n >> m;
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++)
s[i][j] = a[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; //构造前缀和矩阵
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];//注意求和时需要在左下和右上的坐标-1
return 0;
}
差分:
公式:a[n]=b[1]+b[2]+b[3]……+b[n]
b[n]=a[n]-a[n-1]
***如果需要a[n]数组中在[l,r]这个范围中每个数都加c***
只需要在b[l]+c,b[r]-c
当b[l]+c,则a[l]到a[n]的每个数都加上c
当b[r+1]-c,则a[r+1]到a[n]每个数都减c
则实现范围[l,r]中每个a数组中的数都+c
那么如何构造b数组呢?我们可以自己先写一个函数
void insert(int l,int r,int c)
{
b[l]+=c;
b[r+1]-=c;
}
这个函数可以用于 1.构造b数组
2.实现a数组在[l,r]范围内+c
一,构造b数组
for(int i=1;i<n;i++)
{
insert(i,i,a[i]);
}
二,实现a数组在[l,r]范围内+c
insert(l,r,c);//得到处理完毕的b数组
for(int i=1;i<=n;i++)
{
b[i]+=b[]i-1 //每一项依次累加将b数转为a数组
//被转化的b数组为已经在范围[l,r]每一项+c的a数组
}
总结!!!!
1.无论是前缀和还是差分都可以先把a[n]与s[n]或a[n]与b[n]的关系给列出来
2.根据关系创建s[n]/b[n]
3.s[n]可用于求a[n]任意范围内的和,b[n]可用于使a[n]任意范围内加减某个数
其时间复杂度都为0(1)