算法:前缀和与差分
算法:前缀和与差分
一维前缀和
a[N]为一数组,若存在s[N], 使得s[i]=a[1]+a[2]+a[3]+...+a[i], 则称s[N]为a[N]的前缀和数组。
前缀和用来求一个数组内给定区间所有元素的和,将其时间复杂度降为O(1).
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], s[N];
int main()
{
//ios::sync_with_stdio(false); //提高cin读取速度,使scanf失效
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + a[i]; //前缀和初始化
while (m--)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", s[r] - s[l - 1]); //区间和的计算
}
return 0;
}
二维前缀和
二维前缀和与一维的类似,即s[i][j]是(i,j)位置的左上部分的和。
// 子矩阵的和
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], s[N][N];
int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
scanf("%d", &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]; // 求前缀和
while (q--)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]); // 算部分和
}
return 0;
}
差分
差分可以看作是前缀和的逆运算。对于一个数组a[N],如果存在b[N],使得a[N]是b[N]的前缀和,那么则称b[N]是a[N]的差分。
差分可以很快速地将一个数组中的一段区间内的数加上一个数值,只需要在其差分数组的这个区间内的第一个数加上这个数,最后一个数减去这个数即可。
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
void insert(int l, int r, int c)
{
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++)
{
insert(i, i, a[i]); //将a[n]看作是全为0的数组每次在一个位置上插入a[i]
}
while (m--)
{
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for (int i = 1; i <= n; i++)
{
b[i] += b[i - 1];
}
for (int i = 1; i <= n; i++)
printf("%d", b[i]);
return 0;
}
二维差分
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &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--)
{
int 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++)
{
printf("%d", b[i][j]);
puts("");
}
return 0;
}