前缀和与差分

发布时间 2023-04-30 02:37:19作者: 邪童

前缀和

原数组: 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])