1. 程式人生 > >牛客網小白月賽5

牛客網小白月賽5

目描述

    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;
}