差分个人见解(一)

一维差分

什么是差分

在这里插入图片描述
前缀和或许你已经了解了,差分其实就是前缀和的逆运算。

假设 a1 到 an 为 b1到 bn 的前缀和。

那么 b1 到 bn,分别就是 a1 到 an 的 差分。

差分的每一项等于 原序列对应项 减去 前一项。

构造差分数组

构造差分数组有两种方式,第一种是利用下列递推公式遍历一遍数组。
在这里插入图片描述
其中 数组 a 为 原数组,数组 b 为要构造的差分数组。

这里跟前缀和那里一样,i 不会 取到 0,数组前都会留一个空位,从1开始存储。

第二种构造方式我们一会 会说到。

差分数组的用处

差分数组可以快速 使一个区间内加上一个数。

我们来看下面的例子,还是假设 a为原序列,数组b 为 a 的差分数组。

假设我们的目标是 3 到 5 这个区间内所有数字都加上 c。
在这里插入图片描述
有了差分数组后,我们可以这样做。

在这里插入图片描述
首先给 b3 加c。

此时我们如果求 数组b 的新前缀和数组,如果覆盖数组a,那么 a3 到 an都会 加上 c。(这个想法很关键)

由于我们的目标是 a3 到 a5 加上 c。

所以需要这样做。
在这里插入图片描述
给 b6 减去c。

这个操作之后,当我们求 数组b 的前缀和数组的时候,a6 到 an 的值都会减去 c。

由此我们便得出了一个公式。

如果我们需要在区间 [ l , r ] 上加一个数 c。

那么我们只需要操作差分数组就可以了,公式如下:
在这里插入图片描述

实战演练

题目

输入一个长度为 n n n 的整数序列。

接下来输入 m m m 个操作,每个操作包含三个整数 l , r , c l, r, c l,r,c,表示将序列中 [ l , r ] [l, r] [l,r] 之间的每个数加上 c c c

请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数 n n n m m m

第二行包含 n n n 个整数,表示整数序列。

接下来 m m m 行,每行包含三个整数 l , r , c l,r,c lrc,表示一个操作。

输出格式

共一行,包含 n n n 个整数,表示最终序列。

数据范围

1 ≤ n , m ≤ 100000 1 \le n,m \le 100000 1n,m100000,
1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrn,
− 1000 ≤ c ≤ 1000 -1000 \le c \le 1000 1000c1000,
− 1000 ≤ 整数序列中元素的值 ≤ 1000 -1000 \le 整数序列中元素的值 \le 1000 1000整数序列中元素的值1000

输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例:

3 4 5 3 4 2

准备阶段:
在这里插入图片描述
其中 数组a 用于存储题目当中的输入数据,数组b 为差分 数组。

输入环节:
在这里插入图片描述
接下来需要构造 差分数组。

还记得刚才的那个区间 +c 的公式吗?我们先把这个行为写成一个函数。

在这里插入图片描述
第二种构造差分数组的思路是 假设刚开始的差分数组都是 0,然后 利用这个 addToRange
将数据加到 差分数组中。
在这里插入图片描述
当然也可以用之前的第一种方法。
在这里插入图片描述
在构造完差分数组后,接下来该处理 m 次询问了。

对于每次询问,输入一个区间 和 区间所加的值。
在这里插入图片描述
接着套函数 就可以了。

最后 我们只需要 求 数组 b 对应的前缀和数组。

这里我们将前缀和 数组也放到 数组b 里面,也就是覆盖掉原数组。

在这里插入图片描述
完整代码如下:

#include <iostream>
using namespace std;

const int N = 1e5+10;
int n, m;
int a[N], b[N];

void addToRange(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)  scanf("%d", &a[i]);
    
    for (int i = 1; i <= n; i++)  addToRange(i, i, a[i]);
    
    while (m--)
    {
        int l, r, c;
        scanf("%d%d%d", &l, &r, &c);
        addToRange(l, r, c);
    }
    
    for (int i = 1; i <= n; i++) b[i] = b[i] + b[i - 1];
    
    for (int i = 1; i <= n; i++) printf("%d ", b[i]);
    
    return 0;
}


这个代码其实有些地方的for循环是 可以合并在一起写的,如果你的思路清晰了,就合并着写。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值