前缀和与差分

本文介绍了前缀和和差分的概念,并通过例题详细讲解了它们的应用。前缀和用于快速求解区间和,避免暴力求解导致的时间超限;差分则是在数组更新操作中发挥作用,通过差分数组简化问题。文章还提供了具体的代码示例,帮助读者理解和掌握这两种技巧。

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

终于不是STL了。

今天,前缀和与差分他来了。

首先,大家听到前缀和这个名字一定不陌生。

前缀和实在是太基础了,不过今天,我们要让前缀和与差分一块来用,先来复习一下前缀和。

前缀和

前缀和也可以前缀积,总体来说就是在一些题目数据当中 nnn 较大,而导致使用暴力 TLETLETLE

来看一道例题(自己想的,前缀和模板):

给定一个数 n(1≤n≤106)n(1 \le n \le 10^6)n(1n106) ,接着给定 nnn 个数 ,每个数 ai(1≤ai≤105)a_i (1\le a_i \le 10^5)ai(1ai105),最后再给定 q(1≤q≤106)q (1 \le q \le 10^6)q(1q106) 组询问,每组询问有两个数 lllr(1≤l,r≤n)r (1\le l,r \le n)r(1l,rn),代表你需要输出ala_lal 一直到 ara_rar 的和。

这样一道看似简单的题,暴力是过不了的。

于是我们可以用到前缀和。

所以就可以省下时间,这里还是把代码给一下吧。

#include<iostream>
using namespace std;
long long a[1000010];//十年oi一场空,不开long long见祖宗。 
int main()
{
	int n,q;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		a[i]=a[i-1]+x;//前缀和 
	}
	cin>>q;
	while(q--)
	{
		int l,r;
		cin>>l>>r;
		cout<<a[r]-a[l-1]<<endl;
	}
	return 0;
}

前缀积同理,将 + 变成 * 就行了。

差分

复习完前缀和,来看看差分。

差分需要用到前缀和。

前缀和好理解,但是差分怎么说?

差分就是 ai−1a_{i-1}ai1aia_iai 的差。

这里使用一道差分例题来讲解。

题目描述

给定数组a[1],a[2],…,a[n],以及q个操作,每个操作由l,r,x三个整数组成,表示对a[l],a[l+1],…,a[r]这一段数组的每个数都加上x(保证l,r大小合法)。请输出最后的数组。

输入格式

第一行一个整数n,表示数组的大小。

第二行n个整数a[i],表示数组。

第三行一个整数q,表示操作的数量。

接下来q行,每行三个整数l,r,x,表示一次操作。

输出格式

n个整数,表示最后数组的情况。

样例输入

5
1 2 3 4 5
3
1 1 1
2 4 -1
3 5 2

样例输出

2 1 4 5 7

问题提示

对于30%的数据,1<=n,q<=100,0<=a[i]<=100,0<=x<=100。

对于60%的数据,1<=n,q<=100000,0<=a[i]<=100,0<=x<=100。

对于100%的数据,1<=n,q<=200000,0<=a[i]<=1e9,0<=|x|<=1e9。

好的,这道题明显暴力过不了。但是乍一看,没有地方用差分啊?那是因为你还不了解差分的优点。

先来维护一下差分数组。

a数组(输入数据)={1,2,3,4,5}

b数组(差分数组)={1,1,1,1,1}

而假设你想将axa_xax一只到aya_yay全部加上zzz

你只需要将bxb_xbx 加上 z 再将 by+1b_{y+1}by+1 减去 z 。

接着将其做前缀和处理即可。

具体看代码。

#include<iostream>
using namespace std;
long long a[200005];//输入数据 
long long b[200005];//差分 
long long c[200005];//前缀和 
int main()
{
	int n,q;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[i]=a[i]-a[i-1];//差分处理 
	}
	cin>>q;
	while(q--)
	{
		int l,r,x;
		cin>>l>>r>>x;//对于每个数据 
		b[l]+=x;//之后都+x 
		b[r+1]-=x;//之后都-x(抵消) 
	}
	for(int i=1;i<=n;i++)
	{
		c[i]=c[i-1]+b[i];//前缀和处理 
		cout<<c[i]<<" ";//输出答案。 
	}
	return 0;
}

就是这么简单,结束,下课!
(别忘了点赞+关注+评论)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值