[算法篇] 简单讲讲一维前缀和与差分

前缀和
先给定义:指某序列的前n项和
是不是与我们高中所学的数列求和类似?

给出用途:

如我们于一组长度为n的整数序列中询问m次,每次询问中输出区间[l,r]中数之和

倘若我们先不使用前缀和,预测一下思路将会是:m次询问中,每一次都求和数组[l,r]
时间复杂度为O(n),思路很简单但若m非常大则将循环很多次,可想而知这并非较优的办法。

回归数列知识,设数列a[n]的前n项和我们设为S[n]
我们要求a[4]到a[10]之和,则可得a[4]+a[10]=S[10]-S[3]即可
所以前缀和便是令S[r]-S[l-1]

接下来便简单了,贴出代码:(于数组a中求区间[l,r]中之和)

复制代码
#include<iostream>
using namespace std;
long long a[100000000],arr[100000000];//全局数组默认每一项都为0

int main() {
    ios::sync_with_stdio, cout.tie(0), cin.tie(0);//这一行是关闭输入输出流的同步,提高程序运行效率,读者可自行去了解
    int m,n;//m为询问次数,n为所需序列长度
    cin >> m >> n;
    for (int i = 1; i <= n; ++i) {//i从1开始
        cin >> a[i];
        arr[i] = arr[i - 1] + a[i];
    }
    while (m--) {
        int l, r;
        cin >> l >> r;
        cout << arr[r] - arr[l - 1] << '\n';
    }
    return 0;
}
复制代码

特别注意:我们这里输入时以i=1为首项,是为了后面i-1时不为-1


前缀和具有良好的查询性质,而差分具有良好的修改性质


差分其实便是前缀和的逆运算,可以快速对数组某一区间进行修改操作

我们需要引入一个辅助数组b[n],令b[i]=a[i]-a[i-1](当i=1时,b[1]=a[1]-a[0],a[0]=0)

以下呈现目的:
我们不妨将b[n]中求和b[1]到b[j]
即b[1]+b[2]+b[3].....+b[j]=(a[1]-a[0]) + (a[2]-a[1]) + (a[3]-a[2]) +....+ (a[j]-a[j-1])
所以则等于a[j],这像不像我们高中时常用的裂项求和?

利用这个如何体现出修改的用途呢?

首先:
a[1]=b[1]
a[2]=b[1]+b[2]
a[3]=b[1]+b[2]+b[3]
a[4]=b[1]+b[2]+b[3]+b[4]
a[n]=b[1]+b[2]+b[3]+b[4]+...+b[n]

假设我们想让[3,n]中的数同时+3
则我们只需令b[3]+3,则a[3]往后数的都会同时+3
如:
a[3]+3=b[1]+b[2]+b[3]+3
a[4]+3=b[1]+b[2]+ (b[3]+3) +b[4]
...
那如果只令一小段,如[3,5]中同时+3呢
我们只需令b[3]+3,再让b[6]-3
我们于草稿纸中画出
不难发现a[3]往后同时+3,再让a[6]往后同时-3,则只有a[3]到a[5]进行了+3的修改

这种方法是否比通过循环令原数组挨个修改快速许多?

解决问题:给定一个长度为𝑛的数组𝑎,进行p次区间同时加x的修改,q次区间求和的查询
以下贴上代码:

复制代码
#include<iostream>
using namespace std;
using ll = long long;
ll a[100000000],arr[10000000],b[100000000];
//考虑可能数据很大所以此处用long long
void insert(int l, int r, int x) {//让数组a[n]在区间[l,r]中同时增加x
    b[l] += x;
    b[r + 1] -= x;
}

int main() {
    ios::sync_with_stdio, cout.tie(0), cin.tie(0);
    int n, p, q;
    cin >> n >> p >> q;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        b[i] = a[i] - a[i - 1];
    }
    while (p--) {//p次修改
        int l, r, x;
        cin >> l >> r >> x;
        insert(l, r, x);
    }
    for (int i = 1; i <= n; ++i){ 
        a[i] = a[i - 1] + b[i];//将b[i] = a[i] - a[i - 1]换下便是此式
        arr[i] = arr[i - 1] + a[i];//前缀和
    }
    while (q--) {//q次询问
        int l, r;
        cin >> l >> r;
        cout << arr[r] - arr[l - 1] << '\n';
    }
    return 0;
}
复制代码

 

posted @   Mashiro-z  阅读(115)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示