区间段加C(一维差分)
注释
给定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-1]无影响
a[L~R]加上了C
a[R+1~N]无影响
在第一个for语句调用insert,
使得b[i]=b[i]-b[i-1]这样使得a[i]=b[1]+b[2]+....+b[i]成立
while里调用insert,使得b[l]+=c;这样由于输出的时候b[l-1]=a[l-1],所以b[l]=c+a[l]
b[r+1]-=c;因为输出的时候b[r]=a[r]+c,所以b[r+1]=b[r+1]+b[r-1]=a[r+1]+c-c=a[r+1]
在第二个for语句,目的是使得b[n]==a[n](加C后的),将修改后的b[n]输出
时间复杂度由o(n)降到了o(1)
代码段
#include<bitsstdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int M = 1010;
int n, m, q;
int a[N], tmp[N], s[N],b[N];
int a1[M][M], s1[M][M];
拆分
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++)b[i] += b[i - 1];
for (int i = 1; i <= n; i++)printf("%d", b[i]);
二维区间加C(二维差分)
给定a[i][j],构造差分矩阵b[i,j],使得a[][]是b[][]的二维前缀和
b[i][j]的通项公式为
差分核心操作:给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵中的所有数a[i,j],加上C
对于差分数组的影响:
b[x1,y1]+=C b[x1,y2+1]-=C
假设(3,3)为(x1,y1),(5,4)为(x2,y2)
注:这里的图示表示的是a[n]即b[n]的前缀和的赋值情况
虽然操作的是b[n],但最后真正影响的是b[n]的前缀和即a[n](因为要输出a[n])
第一个操作将有颜色的部分为被加上C(即后面bn前缀和包含(3,3)的部分)
第二个操作删去了前缀和含有(3,5)的部分的C
b[x2+1,y1]-=C b[x2+1,y2+1]+=C
第三个操作则删去前缀和含有(6,3)部分的C
注意到这里(6,5)又被删去了一次,所以变黑
第四个操作将包含(6,5)的前缀和都加上C后面的元素的前缀和都会加C(恢复原数值)
注释
首先insert函数相当于封装的一个插入函数,实现的功能是
给定了坐标(x1,y1)和(x2,y2),对bn进行四次操作,操作的行列式形式为
+ | - |
- | + |
得到结果为bn的二维前缀和等于加上去的形参C
实现的原理可以见上方图解
最终在输出前,将b[n][m]进行前n,m项累加操作
即
b[i][j] += b[i][j - 1] -b[i - 1][j - 1] + b[i - 1][j];
使得每一项b[i][j]=a[i][j](更新后的新a[i][j])
代码段
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int M = 1010;
int n, m, q;
int a[N], tmp[N], s[N],B[N];
int a1[M][M], s1[M][M],b[M][M];
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", &a1[i][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
insert(i, j, i, j, a1[i][j]);
while (q--)
{
int x1, y1, x2, y2, c;
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 - 1] + b[i - 1][j];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
printf("%d ", b[i][j]);
puts("");
}
return 0;
}