2021-08-18

本文详细介绍了前缀和与差分的概念,并提供了多个示例进行解释,包括一维和二维前缀和的计算,以及一维和二维差分的实现。这些操作在解决数组和矩阵的求和问题以及数据更新问题中非常有用。通过实例代码展示了如何在C++中应用这些方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前缀和,差分

定义

一维前缀和

s[r]=1 + 2 + 3 +…+ l-1 + l + … + r;
s[r] - s[l-r] = a[l] + … + a[r];

二维前缀和

s[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
s[x2, y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];

一维差分

给区间[l, r]中的每个数加上c:
s[l]+=c, s[r+1]-=c;

二维差分

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有 元素加上c:
s[x1][y1]+=c, s[x2+1][y1]-=c, s[x1][y2+1]-=c, s[x2+1][y2+1]+=c;

例题

/* 一维前缀和 --------------------------------------------------------------------*/
/* 输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10          */

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N =10e+4;
int n, m,a[N],s[N];
int main()
{
    memset(s, 0, sizeof(s));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        s[i] = s[i-1] + a[i];
    }
    while(m--)
    {
        int l,r;
        scanf("%d%d", &l,&r);
        printf("%d\n", s[r]-s[l-1]);  
    }
    return 0;
}

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100010;
int s[N];

int main()
{
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ )
        scanf("%d", &s[i]), s[i] += s[i - 1];
    
    while(m -- )
    {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]);
    }
    
    return 0;
}
/* 二维前缀和 ----------------------------------------------------------------------------------*/

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N =1010;

int a[N][N], s[N][N];
signed 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 ++ )
		    s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];//二维前缀和

	while(q -- )
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		printf("%d", s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]);//部分矩阵的和
	}
	int aaa;
	cin >> aaa;
	return 0;
}

//方法二
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int s[N][N];

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", &s[i][j]);
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
    while(q -- )
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
    }
    
    return 0;
}

/* 一维差分-------------------------------------------------------------------------------------------------- */
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N =1e+4;
int n,m,k,a[N], b[N];
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);//一维数据
        b[i] = a[i] - a[i - 1];//原始一维差分
    }
    int l, r, c;
    while (m--)
    {
        scanf("%d%d%d", &l, &r, &c);
        b[l] += c;     //将序列中[l, r]之间的每个数都加上c
        b[r + 1] -= c;//利用差分来改变
    }
    for (int i = 1; i <= n; i++)
    {
        a[i] = b[i] + a[i - 1];//前缀和运算
        printf("%d ", a[i]);
    }
    return 0;
}

/* 二维差分--------------------------------------------------------------------------------------------------------------- */
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N =1e+4;
int n,m,k,a[N][N], b[N][N];
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;
}
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++)
        {
            scanf("%d", &a[i][j]);//二维数据
            insert(i, j, i, j, a[i][j]);//原始二维差分
        }

    while(k--)
    {
        int x1, y1, x2, 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++)
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];//二维

    for(int i = 1;i <= n; i++)
    {
        for(int j = 1;j <= m; j++)
                printf("%d",b[i][j]);
        printf("\n");
    }
    return 0;
}//sn - sn-1= an   差分  a1 + an = sn

/*s上题  输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数x1, y1, x2, y2, c,
其中(x1, y1)和(x2, y2)表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上c。
请你将进行完所有操作后的矩阵输出。
输入格式
第一行包含整数n,m,q。
接下来n行,每行包含m个整数,表示整数矩阵。
接下来q行,每行包含5个整数x1, y1, x2, y2, c,表示一个操作。
输出格式
共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。
数据范围
1≤n,m≤1000,
1≤q≤100000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤c≤1000,
−1000≤矩阵内元素的值≤1000

输入样例
3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1
输出样例
2 3 4 1
4 3 4 1
2 2 2 2
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值