C++ 前缀和&差分

文章介绍了前缀和算法,它能将区间和的求解从O(n)优化到O(1),并通过示例代码展示了如何实现。同时,文章也解释了差分算法,用于将区间加法操作高效处理,通过一次前缀和计算得到最终结果。

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

前缀和

1. 这是什么东东 

它是一种算法,可以将O(n)的速度转换成O(1)的速度,快速求出区间和与区间乘积。

2. 如何实现

举个例子洛谷P8218这道区间求和的题。

#include<bits/stdc++.h>
using namespace std;
long long n,m,a[100005],sum[100005],l,r;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];//sum[i]为区间[1,i]的和,不停的叠加。
    }
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>l>>r;//输入区间。
        cout<<sum[r]-sum[l-1]<<'\n';//输出区间和。
    }
}
定义:sum[r]-sum[l-1]为区间[l,r]的和。

差分 

1. 这又是什么东东 

它也是一种算法,可以将n次O(n)的区间加与区间减操作变成n次O(1)的加法运算加一次前缀和。

2. 如何实现

以下是区间加的代码。

#include<bits/stdc++.h>
using namespace std;
long long n,m,a[100005],add[100005],sum,l,r,x;
int main(){
    cin>>n;//输入数组的长度。
    for(int i=1;i<=n;i++)cin>>a[i];//输入数组的每一个数。
    cin>>m;//输入要进行区间加的次数。
    for(int i=1;i<=m;i++){
        cin>>l>>r>>x;//输入要进行加法运算的区间,与要加的数。
		add[l]+=x;
		add[r+1]-=x;
    }
    for(int i=1;i<=n;i++){
   	    add[i]+=add[i-1];//设add[i]为add数组[1,i]的和。
		//add[i]现在为数组第i个数要加的数。
		a[i]+=add[i];
	}
	for(int i=1;i<=n;i++)cout<<a[i]<<' ';//输出数组的每一个数。
}

定义:差分数组进行前缀和后为我们想要的数组。

### C++前缀和差分的概念及实现 #### 前缀和概念 对于一个数 `a`,前缀和是指一个新的数 `s`,其中每一个位置 `i` 的元素等于原数从第一个元素到当前位置所有元素之和。即 \( s[i] = a[0] + a[1] + \ldots + a[i] \)[^2]。 #### 差分概念 差分是一种用于快速处理区间增减问题的技术。给定一个数 `b` 表示原始数值变化情况,则可以通过构建差分来简化多次区间的修改操作。具体来说,在某个范围内增加或减少固定值时只需对该范围两端做相应标记即可完成整体调整[^3]。 #### 实现方法 ##### 单维前缀和 下面展示如何利用C++编写单维度的前缀和程序: ```cpp #include &lt;iostream&gt; using namespace std; const int N = 1e6 + 10; int main(){ int n, m; // 数长度n以及询问次数m int a[N], s[N]; cin &gt;&gt; n &gt;&gt; m; for (int i = 1; i &lt;= n; ++i){ cin &gt;&gt; a[i]; } // 计算前缀和 for (int i = 1; i &lt;= n; ++i){ s[i] = s[i - 1] + a[i]; } while (m--){ int l, r; cin &gt;&gt; l &gt;&gt; r; // 输出查询结果 cout &lt;&lt; s[r] - s[l - 1] &lt;&lt; endl; } } ``` 这段代码首先读取了一个整数序列并计算它的累积和(也就是所谓的&ldquo;前缀和&rdquo;),之后可以根据用户给出的不同子段起点终点迅速求得该段内所有数字总和而无需重复累加过程[^1]。 ##### 差分的应用实例 当面对频繁更新特定区间内的值的任务时,可以采用如下方式优化效率: 假设有一个初始全零的一维向量 `diff[]` 来记录增量信息。每当需要对 `[l,r]` 范围内的每个元素都加上常数c时,只需要执行两步操作: - 对于左边界的位置 `l` 处设置增加值 c; - 如果存在右边界右边的第一个位置 `r+1` ,则在此处设下负增长 `-c` 以便抵消之前的影响。 最后再通过对这个异表进行一次简单的线性扫描就能恢复出最终的结果列表了。 ```cpp void applyDifference(int diff[], int length, vector&lt;pair&lt;int,int&gt;&gt;&amp; updates) { fill(diff, diff + length, 0); for(auto&amp; update : updates){ int start = update.first; int end = update.second.first; int value = update.second.second; diff[start] += value; if(end + 1 &lt; length) diff[end + 1] -= value; } } vector&lt;int&gt; getFinalValues(const int original[], const int diff[], int size) { vector&lt;int&gt; result(size); result[0] = original[0] + diff[0]; for(int i = 1 ; i != size ; ++i ) result[i] = result[i-1] + diff[i]; return result; } ``` 上述函数展示了怎样高效地批量应用多个区间上的增值指令,并且能够轻松获取任意时刻的状态快照。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值