前缀和:
有一个长度为n的数组:a1, a2, a3, … , an。
前缀和si = a1 + a2 + a3 + … + ai。
作用:快速求出数组某一个区间的和
同理,我们可以推广到二维、三维等等。
前缀和最主要的就是思维
求解:
一维前缀和:
const int N = 1e5 + 10;
int a[N], s[N], t;
for (int i = 1; i <= n; i ++ ) cin >> a[i];//原数组
for (int i = 1; i <= n; i ++ ) s[i] = a[i] + s[i - 1];//前缀和数组
快速求出区间[ l, r]之间的和
cin >> l >> r;
cout << s[r] - s[l - 1] << endl;
二维前缀和:
const int N = 1e5 + 10;
int a[N], s[N];
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];//前缀和数组
快速求出(x1, y1)和(x2, y2)两点之间矩阵的和
s = s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1];
差分:
本质:前缀和的逆运算
有一个长度为n的a数组:a1, a2, a3, … , an。
现在构造一个b数组:b1, b2, b3, … , bn。
使得a数组是b数组的一个前缀和数组,
即 ai = b1 + b2 + b3 + … + bi;
即a数组是b数组的前缀和,b数组是a数组的差分。
作用:用于对一个区间的数进行加减操作,将复杂度从O(n)降到O(1)。
例如:
将【l, r】 区间的每一个数都加上C;
利用差分数组,只需将b[l] + C, b[r + 1] - C。
一维差分数组:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
void insert (int l, int r, c)
{
b[l] += c;
b[r + 1] -= c;
}
int main ()
{
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) insert(i, i, a[i]);//相当于在[i, i]区间每一个数加上a[i],构造差分数组
//对[l,r]所有的数加上一个x
while (cin >> l >> r >> x) insert (l, r, x);
for (int i = 1; i <= n; i ++ ) b[i] += b[i - 1];//求解操作后的a数组,即b的前缀和数组
for (int i = 1; i <= n; i ++ ) cout << b[i] << " ";
cout << endl;
return 0;
}
二维差分数组:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N], b[N];
void insert (int x1, int y1, int x2, int y2, int x)
{
b[x1][y1] += x;
b[x1][y2 + 1] -= x;
b[x2]
}
int main ()
{
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 ++ )
insert (i, j, i, j, a[i]);
//构造差分数组
while (cin >> x1 >> y1 >> x2 >> y2 >> x) insert (x1, y1, x2, y2, x);
}
二维差分数组未编完