终于不是STL了。
今天,前缀和与差分他来了。
首先,大家听到前缀和这个名字一定不陌生。
前缀和实在是太基础了,不过今天,我们要让前缀和与差分一块来用,先来复习一下前缀和。
前缀和
前缀和也可以前缀积,总体来说就是在一些题目数据当中 nnn 较大,而导致使用暴力 TLETLETLE 。
来看一道例题(自己想的,前缀和模板):
给定一个数 n(1≤n≤106)n(1 \le n \le 10^6)n(1≤n≤106) ,接着给定 nnn 个数 ,每个数 ai(1≤ai≤105)a_i (1\le a_i \le 10^5)ai(1≤ai≤105),最后再给定 q(1≤q≤106)q (1 \le q \le 10^6)q(1≤q≤106) 组询问,每组询问有两个数 lll 和 r(1≤l,r≤n)r (1\le l,r \le n)r(1≤l,r≤n),代表你需要输出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}ai−1 和 aia_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;
}
就是这么简单,结束,下课!
(别忘了点赞+关注+评论)