前缀和与差分
前缀和
原数组:
a1
,a2
,a3
, \(\cdots\) ,an
前缀和数组:
si
=a1
+a2
+ \(\cdots\) +ai
,s0 = 0
① 如何求前缀和数组
Si
:Si
=Si-1
+ai
,s0 = 0
② 前缀和数组的作用: 快速地求出原数组中一段数的和
一维前缀和
S[i]
=S[i-1]
+a[i]
=a[1]
+a[2]
+ \(\cdots\) +a[i]
a[l]
+ \(\cdots\) +a[r]
=S[r]
-S[l-1]
二维前缀和
S[i,j]
表示a[i,j]
左上角全部元素的和
S[i,j]
=a[i,j]
+S[i-1,j]
+S[i,j-1]
-S[i-1,j-1]
二位前缀和的作用: 快速求出矩阵数组中子矩阵的和
a[x1,y1]
(左上角) 到a[x2,y2]
(右下角) 的矩阵的元素之和为:
S[x2,y2]
-S[x2,y1-1]
-S[x1-1,y2]
+S[x1-1,y1-1]
差分
差分, 即前缀和的逆运算
原数组:
a1
,a2
,a3
, \(\cdots\) ,an
构造差分数组:
b1
,b2
,b3
, \(\cdots\) ,bn
使得
ai
=b1
+b2
+ \(\cdots\) +bi
一维差分
构造
bi
=ai
-ai-1
,a0 = 0
b1
=a1
b2
=a2
-a1
b3
=a3
-a2
\(\quad\) \(\cdots\)
bn
=an
-an-1
由差分数组
b[]
可推原数组a[]
ai
=b1
+b2
+ \(\cdots\) +bi
操作: 对数组
a[]
, 区间[l,r]
内所有数加c
只需
b[l] += c
,b[r+1] -= c
ai
=b1
+b2
+ \(\cdots\) +bi
思想: 原数组
a[]
全0
, 差分数组b[]
也全0
给
a[1]
赋值a1
\(\Leftrightarrow\) 对区间[1,1]
内数加a1
\(\Leftrightarrow\)b1 += a1
,b2 -= a1
void insert (int l,int r,int c)
{
b[l]+=c;
b[r+1]-=c;
}
初始化:
insert (i,i,a[i])
二维差分
原数组
a[i][j]
, 构造差分数组S[i][j]
a[i][j]
表示S[i][j]
左上角全部元素之和
S[i][j] + = c
\(\longrightarrow\)a[i][j]
右下角所有元素加c
给
a[x1,y1]
(左上角) 到a[x2,y2]
(右下角) 的矩阵内所有元素加上c
:
b[x1][y1] += c
,b[x2+1][y1] -= c
,b[x1][y2+1] -= c
,b[x2+1][y2+1] += c
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;
}
初始化:
insert(i,j,i,j,a[i][j])