链接:https://www.nowcoder.com/acm/contest/135/I
来源:牛客网
题目描述
Apojacsleam喜欢数组。
他现在有一个n个元素的数组a,而他要对a[L]-a[R]进行M次操作:
操作一:将a[L]-a[R]内的元素都加上P
操作二:将a[L]-a[R]内的元素都减去P
最后询问a[l]-a[r]内的元素之和?
请认真看题干及输入描述。
输入描述:
输入共M+3行:
第一行两个数,n,M,意义如“题目描述”
第二行n个数,描述数组。
第3-M+2行,共M行,每行四个数,q,L,R,P,若q为1则表示执行操作2,否则为执行操作1
第4行,两个正整数l,r
输出描述:
一个正整数,为a[l]-a[r]内的元素之和
示例1
输入
10 5
1 2 3 4 5 6 7 8 9 10
1 1 5 5
1 2 3 6
0 2 5 5
0 2 5 8
1 4 9 6
2 7
输出
23
说明
先贴按照题意遍历的代码(TLE):时间复杂度O(n^2)
#include<bits/stdc++.h>
using namespace std;
int a[1000000];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
while(m--)
{
int q,l,r,p;
scanf("%d%d%d%d",&q,&l,&r,&p);
if(q==1)
{
for(int i=l;i<=r;i++)
a[i]-=p;
}
else
{
for(int i=l;i<=r;i++)
a[i]+=p;
}
}
int tl,tr;
long long sum=0;
scanf("%d%d",&tl,&tr);
for(int i=tl;i<=tr;i++)
sum+=a[i];
printf("%lld\n",sum);
return 0;
}
看了别人的博客,知道了一种叫做前缀和的东西,下面我就来说说什么叫做前缀和
b[i]表示a[1],a[2],......,a[i]的和
for(int i=1;i<=n;i++)
b[i]=b[i-1]+a[i];
差分:
我们对区间[l,r]都加上p的时候,令b[l]+=p,b[r+1]-=p,如果执行b[i]+=b[i-1],那么此时的b[i]就是a[i]要修改的数字,修改a[i],最后在[l,r]这个区间内遍历求和就OK了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int a[1000001],b[1000001];
int main()
{
memset(b,0,sizeof(b));
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
while(m--)
{
int q,l,r,p;
scanf("%d%d%d%d",&q,&l,&r,&p);
if(q==1)
{
b[l]-=p;
b[r+1]+=p;
}
else
{
b[l]+=p;
b[r+1]-=p;
}
}
int tl,tr;
scanf("%d%d",&tl,&tr);
long long sum=0;
for(int i=1;i<=n;i++)
{
b[i]+=b[i-1];
a[i]+=b[i];
}
for(int i=tl;i<=tr;i++)
sum+=a[i];
printf("%lld\n",sum);
return 0;
}