一维前缀和
简介
前缀和用来计算任意区间和
a数组是原数组,b数组是a数组的前缀和
S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]
模板题
模板题分析
- 看到求l~r的区间和,想到用前缀和
- 求数组a的前缀和
s[i] = s[i - 1] + a[i];
- 最后输出注意l与r的大小关系,所以要判断一下
if (l <= r)
cout << s[r] - s[l - 1] << endl;
else
cout << s[l] - s[r - 1] << endl;
模板题代码
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], s[N];
int main() {
cin >> n >> m;
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--) {
int l, r;
cin >> l >> r;
if (l <= r)
cout << s[r] - s[l - 1] << endl;
else
cout << s[l] - s[r - 1] << endl;
}
return 0;
}
二维前缀和
简介
与一维前缀和类似
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
模板题
模板题分析
- a是原数组,s是前缀和,s[i][j]表示i,j这个点左上放所有数的和
- 初始化前缀和数组
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
- 计算(x1,y1)为右下角,(x2,y2)为右上角的子矩阵中所有数的和
printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
模板题代码
//二维前缀和 模板
#include <iostream>
using namespace std;
int n, m, q;
const int N = 1010;
//a是原数组,s是前缀和
int a[N][N], s[N][N];
//s[i][j]表示i,j这个点左上放所有数的和
int main() {
//读入规模较大,建议用scanf来读入
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]);
//计算前缀和s[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--) {
int x1, x2, y1, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
//计算(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;
}
一维差分
简介
- 通过差分数组对原数组在区间[ l , r ]内进行加或减去数的操作,由O(n) 的时间复杂度,优化为O(1)的时间复杂度
- 差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减
模板题
模板题分析
- 给定数组a[1],a[2],…,a[n],构造差分数组b[N],使得
a[i] = b[1]+b[2]+...+b[i]
- 核心操作:
将a[L~R]全部加上C,等价于b[L]+=C,b[R+1]-=C
- 效果:
a[1~L]无影响
a[L~R]加上了C
a[R+1~N]无影响
模板题代码
//差分:
//给定数组a[1],a[2],...,a[n],
//构造差分数组b[N],
//使得a[i] = b[1]+b[2]+...+b[i]
//核心操作:
//将a[L~R]全部加上C,等价于b[L]+=C,b[R+1]-=C
//效果:
//a[1~L]无影响
//a[L~R]加上了C
//a[R+1~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]);
while (m--) {
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for (int i = 1; i <= n; i++)
a[i] = a[i - 1] + b[i];
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
return 0;
}
二维差分
简介
与一维差分类似,只是数组开的是二维数组
模板题
模板题分析
- 差分矩阵
给定原矩阵a[i][j],构造差分矩阵b[i][j],使的a[][]是b[][]的二维前缀和 - 差分核心操作:
给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的所有数a[i][i],加上C - 对于差分影响:
S[x1][x2]+=C
S[x1][y2+1]-=C
s[x2+1][y1]-=C
s[x2+1][y2+1]+=C
模板题代码
//差分矩阵
//给定原矩阵a[i][j],构造差分矩阵b[i][j],使的a[][]是b[][]的二位前缀和
//差分核心操作:
//给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的所有数a[i][i],加上C
//对于差分影响:
//S[x1][x2]+=C
//S[x1][y2+1]-=C
//s[x2+1][y1]-=C
//s[x2+1][y2+1]+=C
#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[x1][y2 + 1] -= c;
b[x2 + 1][y1] -= 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, x2, y1, 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];
a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
// printf("%d ", b[i][j]);
printf("%d ", a[i][j]);
puts(" ");
}
return 0;
}
最后输出的时候,用数组a写一遍二维前缀和公式,最后输出a[i][j],或者用b差分数组求数组加完之后的值都可以。