前缀和与差分:从一维到二维(下)

书接上回

我们之前已经学习了一维的前缀和与差分
现在,让我们拓展一个维度,来到二维。
相信有了前面的基础
学起这些来一定不会很难

二维前缀和

概念

让我们先温习一下一维前缀和的内容

假设: b [ i ] = a [ 1 ] + a [ 2 ] + a [ 3 ] + . . . . . . a [ i ] b[i]=a[1]+a[2]+a[3]+......a[i] b[i]=a[1]+a[2]+a[3]+......a[i]
则a[i]至a[j]的区间和为 b [ j ] − b [ i ] b[j]-b[i] b[j]b[i]

sum[j]-sum[i]...好像打错了,不管他吧

而二维前缀和自然就是要拓展到平面了 如图
便是一整个平面的数据总和
(其实 s u m [ i ] [ j − 1 ] sum[i][j-1] sum[i][j1] s u m [ i − 1 ] [ j ] sum[i-1][j] sum[i1][j]里面都包含着 s u m [ i − 1 ] [ j − 1 ] sum[i-1][j-1] sum[i1][j1]
在这里插入图片描述
我们稍微改一下上面的图片:
在这里插入图片描述
其实紫色区域(看得到的)就是 a [ i ] [ j ] a[i][j] a[i][j]
稍微用一下容斥原理:
我们可以得到: s u m [ i ] [ j ] = s u m [ i ] [ j − 1 ] ( 蓝 加 黄 ) + s u m [ i − 1 ] [ j ] ( 红 加 黄 ) − s u m [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] sum[i][j]=sum[i][j-1](蓝加黄)+sum[i-1][j](红加黄)-sum[i-1][j-1]+a[i][j] sum[i][j]=sum[i][j1]()+sum[i1][j]()sum[i1][j1]+a[i][j]
这样对于二维区间和的查询,也可以维持在 O ( 1 ) O(1) O(1)

例题

二维前缀和

题目描述

给出一 m m m n n n列的矩阵, q q q次询问左上角为 ( x 1 , y 1 ) (x1,y1) (x1,y1),右下角为 ( x 2 , y 2 ) (x2,y2) (x2,y2)的子矩阵中数的和

输入格式

第一行三个整数 n , m , q n,m,q n,m,q

之后 行每行 个数,代表给出的矩阵

之后 行每行四个整数 表示一次询问

输出格式

共 行,每行一个整数表示答案

样例

输入样例

3 3 2
0 0 1
1 1 0
1 0 1
1 1 3 3
2 1 2 3
输出样例

5
2

代码
#include<bits/stdc++.h>
using namespace std;
int a[1005][1005];
long long sum[1005][1005],ms;
int main(){
    ios::sync_with_stdio(false);//加快cin读入(当然你用scanf可以不用管这些)
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
        	cin>>a[i][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]+a[i][j];//前缀和计算过程
		}
    }
    for(int i=1;i<=q;i++){
    	int a1,b1,a2,b2;
    	cin>>a1>>b1>>a2>>b2;
    	cout<<sum[a1-1][b1-1]+sum[a2][b2]-sum[a1-1][b2]-sum[a2][b1-1]<<endl;//区间查询
	}
}

二维差分

概念

还是那句话:
差分是前缀和的逆运算
这句话放到二维里肯定也是适用的
a [ i ] [ j ] a[i][j] a[i][j] b [ i ] [ j ] b[i][j] b[i][j]的二维前缀和
因为二维差分跟二维有关系,所以区间修改的是一整个平面的值
这里画个图示意一下
图1:
在这里插入图片描述
我们修改的是 b b b数组的黄色区域,但是 a a a数组整个蓝色区域也跟着黄色做了同样的修改(想一想,为什么)
要做到区间修改还需要这样

图2图3图4

在这里插入图片描述
当黄色区域改变后,所有非灰色区域会随着黄色区域的改变而改变
再小小的用一下容斥
设图 n n n随黄改变的地方为 S n S_n Sn
显然
在这里插入图片描述
红圈内部分为
S 1 − S 2 − S 3 + S 4 S_1-S_2-S_3+S_4 S1S2S3+S4
所以修改区间的操作只需要加加减减就可以了

代码实现

对于这个更方便的操作是 i n s e r t insert insert(插入)
具体代码如下

int a[10005][10005],b[10005][10005];
void insert(int a1,int a2,int b1,int b2,int c){\\既可以构造也可以修改,21
	b[a1][b1]+=c;
	b[a1][b2+1]-=c;
	b[a2+1][b1]-=c;
	b[a2+1][b2+1]+=c;
}

后面再计算 b b b的二维前缀和就行了
自此前缀和与差分的内容已经讲完了,更多的拓展知识也应该建立在这些基础之上。
如果还感兴趣,就自己去探索吧!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值