牛客小白月赛5——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
说明
反思:
一看见区间操作就头脑发热,上去就写线段树,然后超内存错误了五六发........
树状数组倒是可以直接过,线段树其实也行,只要别开lazy数组就行(开习惯了——头巨铁)。
今天又回过头来看这个题,发现只有一次查询,那么用前缀和更快且好写。看了别人的代码发现有人把每个数处理成前一个数的差值,最后再还原回来。个人觉的这个方法麻烦而且代码又长又慢,我这里多开了一个数组,最后只需要for循环一遍[1,R]就行。
PS:以后查询只有一次的时候先想想前缀和。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+10;
long long board[MAXN];
long long Add[MAXN];
int main(){
int N,M;
long long d;
int a,b,c;
while(scanf("%d %d",&N,&M) == 2){
memset(Add,0,sizeof Add);
for(int i=1 ; i<=N ; ++i)scanf("%lld",&board[i]);
for(int i=1 ; i<=M ; ++i){
scanf("%d %d %d %lld",&a,&b,&c,&d);
if(a == 1){
Add[b] -= d;
Add[c+1] += d;
}
else {
Add[b] += d;
Add[c+1] -= d;
}
}
long long add = 0;
long long sum = 0;
int L,R;
scanf("%d %d",&L,&R);
for(int i=1 ; i<=R ; ++i){
add += Add[i];
if(i>=L && i<=R)sum += add+board[i];
}
printf("%lld\n",sum);
}
return 0;
}