ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

差分与前缀和

2022-02-16 12:03:25  阅读:178  来源: 互联网

标签:y2 前缀 int 差分 y1 maxn x2 x1


    差分和前缀和其实是一对逆操作,这里将会对前缀和和差分是怎么实施的,如何理解,以及对应一维和二维数组的情况。

 

    前缀和:换言之,就是前n项和,也就是高中学习数列时的Sn;

       Sn = a1+a2+……an;

       Sn+1 = a1+a2+……an+an+1 = Sn+an+1;

    应用:如果要求从l到r的数字之和,我们不需要遍历求和了,只需要调用前缀和序列的Sr和Sl-1,ans = Sr - Sl-1;

               求(x1,y2) 到 (x2,y2)这个子矩阵之和又怎么求呢?  

     二维数组求前缀和

               首先,我们要明白前缀和数组中的这个b[i][j]代表了什么 ;

               

               因为求的是子矩阵之和,我们的b[i][j]表征的是从[1][1]到[i][j]的子矩阵之和;

 

               那么(x1,y1) 到 (x2,y2)的子矩阵之和  ans = b[x2][y2] -b[x1-1][y2] -b[x2][y1-1] +b[x1-1][y1-1] ;

               图示:

               

 

                       亮橙色是最终需要的,我们剪掉两个红色部分后,还应加上被重复减去的蓝色部分。

        

                    板子

                    

#include<bits/stdc++.h>
#define maxn 1005

using namespace std;
int a[maxn][maxn],b[maxn][maxn];

int main()
{
int n,m,q;
cin >> n >> m >> q;
//进行数据的读入
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d",&a[i][j]);
//进行数据的处理,求前缀和
for(int i = 1;i <= n; i++){
for (int j = 1; j <= m; j ++ ){
b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j];
}
}
//进行查询
for(int i = 1; i <= q; i++){
int x1,x2,y1,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
printf("%d\n",b[x2][y2]-b[x2][y1-1]-b[x1-1][y2]+b[x1-1][y1-1]);
}
return 0;
}

 

                 差分:因为一维和二维不同,我们可以单纯的将差分理解为前缀和的逆运算。

                 应用:可以多次维护一个区间内数据的修改。

                 一维的情况:b[i] = a[i] -a[i-1];           b[l]+=c;    b[r+1]-=c;

                 二维的情况:对于(x1,y1), (x2,y2) 子矩阵加c,因为这是差分矩阵,我们做如下操作;

                   

                                b[x1][y1]+=c;
                                b[x1][y2+1]-=c;
                                b[x2+1][y1]-=c;
                                b[x2+1][y2+1]+=c;

                  图示:

                

 

                                 橙色部分是指+=c的操作对于求前缀和的时候会直接管到矩阵右下角,红色部分是用于-=c抵消掉+=c的操作,而蓝色部分是因为重复了一次-                     =c 的操作,需要单独+=c一次用于抵消。

               值得注意的是,我们为了得到差分矩阵,我们先令其中的值全部为0,然后再把插入原矩阵中的值,相当于给(i,j)到(i,j)进行加1操作.

       所以我们可以单独写一个insert函数。

               

                   板子:

 

#include<bits/stdc++.h>
#define maxn 1005

using namespace std;
int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];

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()
{
int n,m,q;
cin >> n >> m >> q;
//进行数据的读入
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d",&a[i][j]);
//先输入原来的值
for (int i = 1; i <= n; i ++ ){
for (int j = 1; j <=m; j ++ ){
insert(i,j,i,j,a[i][j]);
}
}
//进行改变值的操作
for(int i = 1; i <= q; i++){
int x1,x2,y1,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 ++ ){
c[i][j]=c[i-1][j]+c[i][j-1]-c[i-1][j-1]+b[i][j];
}
}
//输出ans
for(int i = 1;i <= n; i++){
for (int j = 1; j <= m; j ++ ){
printf("%d ",c[i][j]);
}
printf("\n");
}
return 0;
}

               

标签:y2,前缀,int,差分,y1,maxn,x2,x1
来源: https://www.cnblogs.com/ZheyuHarry/p/15899827.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有