牛客小白月赛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;
}

 

posted @ 2018-07-23 10:15  Assassin_poi君  阅读(148)  评论(0编辑  收藏  举报