链接: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
开始看到这道题目上去第一反应线段树模板代码,然后就陷入了内存超限和WA的死循环,从开始的30%一直到最后的%90...WA了七八次...
到后面实在想不到解决方案了就百度了一下这道题的解法, 发现原来还有前缀和这种美滋滋的东西, 简直妙蛙种子啊~~~
关键点: 因为最后只要查询一次,在过程中仅仅只需要对这一段距离进行操作,因为输入顺序的关系可以现将操作的数给保存下来,到后面在统一进行操作, 然后用一个数事先计算出L - R的和,然后每次操作就仅仅只对这个和进行操作。
秒啊~~~~~~
下面附上代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1000001;
int sz[maxn];
int q[maxn],l[maxn],r[maxn],p[maxn];
int n,m;
int tl,tr;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",sz+i);
for(int i=1;i<=m;i++)
scanf("%d%d%d%d",q+i,l+i,r+i,p+i);
scanf("%d%d",&tl,&tr);
ll sum=0;
for(int i=tl;i<=tr;i++) sum += sz[i];
for(int i=1;i<=m;i++){
if(q[i] == 1) p[i] = 0-p[i];
if(r[i]<tl || l[i]>tr) continue;
sum += (min(r[i],tr) - max(l[i],tl) + 1)*p[i];
}
printf("%lld",sum);
return 0;
}