前缀和和差分数组

前缀和

学习参考视频:STUACM-算法入门-前缀和与差分(含二维)_哔哩哔哩_bilibili

一维前缀和

前缀和:给定数组 a r r [ 0.. N ] arr[0..N] arr[0..N] s u m [ i ] sum[i] sum[i]表示 a r r [ 0... i ] arr[0...i] arr[0...i]区间和。

{ s u m [ 0 ] = a r r [ 0 ] , i = 0 s u m [ i ] = s u m [ i − 1 ] + a r r [ i ] , i > 0 \begin{cases} sum[0]=arr[0] &,i=0 \\ sum[i] = sum[i-1]+arr[i]&,i>0 \\ \end{cases} {sum[0]=arr[0]sum[i]=sum[i1]+arr[i],i=0,i>0

实际应用——区间和:sum(L,R) 表示 a r r [ L . . . R ] arr[L...R] arr[L...R]的区间和。暴力计算时间复杂度为 O ( N ) O(N) O(N)
s u m ( L , R ) = { s u m [ R ] , L = 0 s u m [ R ] − s u m [ L − 1 ] , L > 0 sum(L,R) = \begin{cases} sum[R]&,L=0 \\ sum[R]-sum[L-1] &,L>0\\ \end{cases} sum(L,R)={sum[R]sum[R]sum[L1],L=0,L>0

一维差分

区间加法: add(L,R,v): a r r [ L . . . R ] arr[L...R] arr[L...R]的每个数加上v

差分数组: d d d a c c acc acc的差分数组,且 d d d的前缀和 s u m d sum_d sumd即为原数组 a c c acc acc

d [ i ] = { a r r [ i ] − a r r [ i − 1 ] , i > 0 a r r [ i ] , i = 0 d[i] = \begin{cases} arr[i] - arr[i-1] &,i>0 \\ arr[i] &,i=0\\ \end{cases} d[i]={arr[i]arr[i1]arr[i],i>0,i=0

实际应用——累计区间加法:区间操作add(L,R,v) 等价于 d [ L ] + v , d [ R + 1 ] = v d[L]+v, d[R+1]=v d[L]+v,d[R+1]=v

  • 原因分析

    • d[L]+v,是指arr[L…N]都加上v

    • d[R+1]-v,是指arr[R+1…N]都减去v,以抵消d[L]+v对[R+1…N]的影响

  • 复杂度分析
    数组长度N,M次操作,则为 O ( M + N ) O(M+N) O(M+N)

  • 应用场景:

    • 多次操作一次询问:差分数组

    • 一次操作一次询问:线段树

一般情况下,不会基于arr记录结果差分,而是基于全0数组记录操作差分,通过前缀和得到总的操作 Δ d \Delta d Δd,原数组最后的结果为 a r r + Δ d arr + \Delta d arr+Δd

二维前缀和

给定矩阵 M [ n × m ] M[n\times m] M[n×m]

矩阵和:sum(a,b,c,d),(a,b)到(c,d)的和,即以(a,b)和(c,d)为对角顶点的矩阵和,暴力计算时间复杂度为 O ( n m ) O(nm) O(nm)

定义 s u m [ i ] [ j ] sum[i][j] sum[i][j] 是从(0,0)到(i,j)的和
{ s u m [ 0 ] [ j ] = s u m [ 0 ] [ j − 1 ] + M [ 0 ] [ j ] , i = 0 , j ≠ 0 s u m [ i ] [ 0 ] = s u m [ i − 1 ] [ 0 ] + M [ i ] [ 0 ] , i ≠ 0 , j = 0 s u m [ i ] [ j ] = M [ i ] [ j ] + s u m [ i − 1 ] [ j ] + s u m [ i ] [ j − 1 ] − s u m [ i − 1 ] [ j − 1 ] , o t h e r \begin{cases} sum[0][j] = sum[0][j-1]+M[0][j]&,i=0,j\neq 0\\ sum[i][0] = sum[i-1][0]+M[i][0]&,i\neq0,j= 0\\ sum[i][j] = M[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]&,other \\ \end{cases} sum[0][j]=sum[0][j1]+M[0][j]sum[i][0]=sum[i1][0]+M[i][0]sum[i][j]=M[i][j]+sum[i1][j]+sum[i][j1]sum[i1][j1],i=0,j=0,i=0,j=0,other
矩阵和
s u m ( x 1 , y 1 , x 2 , y 2 ) = { s u m [ x 2 ] [ y 2 ] − s u m [ x 2 ] [ y 1 − 1 ] , x 1 = 0 s u m [ x 2 ] [ y 2 ] − s u m [ x 1 − 1 ] [ y 2 ] , y 1 = 0 s u m [ x 2 ] [ y 2 ] − s u m [ x 1 − 1 ] [ y 1 ] , y 1 = y 2 s u m [ x 2 ] [ y 2 ] − s u m [ x 1 − 1 ] [ y 2 ] − s u m [ x 2 ] [ y 1 − 1 ] + s u m [ x 1 − 1 ] [ y 1 − 1 ] , o t h e r sum(x1,y1,x2,y2) = \begin{cases} sum[x2][y2]-sum[x2][y1- 1]&,x1=0 \\ sum[x2][y2] - sum[x1-1][y2]&,y1=0\\ sum[x2][y2]-sum[x1-1][y1]&,y1=y2 \\ sum[x2][y2] - sum[x1-1][y2]-sum[x2][y1- 1]+sum[x1-1][y1-1]&,other \end{cases} sum(x1,y1,x2,y2)=sum[x2][y2]sum[x2][y11]sum[x2][y2]sum[x11][y2]sum[x2][y2]sum[x11][y1]sum[x2][y2]sum[x11][y2]sum[x2][y11]+sum[x11][y11],x1=0,y1=0,y1=y2,other

void pre_sum(int*){
    sum[0][0] = M[0][0]; // 第一个
    for(int i=1;i<n;i++) sum[i][0] = sum[i-1][0]+M[i][0]; // 第一列
    for(int j=1;j<m;j++) sum[0][j] = sum[0][j-1]+M[0][j]; // 第一行
    for(int i=1;i<n;i++)
        for(int j=1;j<m;j++)
            sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + M[i][j];
}
void get_sum(int x1,int y1, int x2, int y2){
    if(!x1 && !y1) return sum[x2][y2];
    if(!x1) return sum[x2][y2]-sum[x2][y1-1];
    if(!y1) return sum[x2][y2]-sum[x1-1][y2];
    return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}

二维差分

add(x1,y1,x2,y2,v)表示以(x1,y1)和(x2,y2)为对角顶点的部分同时加上v

以下基于全0数组记录操作差分:(原理和一维差分类似,就不列公式了)

int d[n+1][m+1] = {0}; // 边界扩大1,避免右/下边界判断
void add(x1,y1,x2,y2,v){
    d[x1][y1]+=v;
    d[x2+1][y1]-=v;
    d[x1][y2+1]-=v;
    d[x2+1][y2+1]+=v;
}
// 操作结束后,对d求pre_sum,得到delta_d,M+=delta_d即为操作结果
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值