牛客小白月赛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
说明
解题思路:显然这道题要操作的是区间修改,区间查询,但题目中有个坑就是给的内存太少了,用线段树懒标记模板或者是树状数组区间修改+区间查询模板都会超内存,仔细一看这题有一个突破口就是只有一次查询(划重点,如果是多次查询,则应该套公式,否则会超时),并且给定n的最大值只有106,因此我们可以利用树状数组差分求前缀和(实际并没用到树状数组,只是用了一个差分数组来模拟)+一次暴力统计区间[l,r]中所有元素的值即可。关于怎么利用差分来修改区间值和求前缀和,请看这篇:题解报告:Luogu P3368 【模板】树状数组 2(区间修改,单点查询)
AC代码(673ms):
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn=1e6+5; 5 int n,q,p,l,r,k,a[maxn]; 6 int main(){ 7 while(~scanf("%d%d",&n,&q)){ 8 memset(a,0,sizeof(a)); 9 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 10 for(int i=n;i>=2;--i)a[i]-=a[i-1];//利用原数组从后往前差分 11 while(q--){ 12 scanf("%d%d%d%d",&p,&l,&r,&k); 13 if(p==1)k=-k; 14 a[l]+=k,a[r+1]-=k;//区间修改操作 15 } 16 for(int i=2;i<=n;++i)a[i]+=a[i-1];//求前缀和,还原a[i]值 17 scanf("%d%d",&l,&r); 18 LL ans=0; 19 for(int i=l;i<=r;++i)ans+=a[i];//O(n)统计区间[l,r]所有元素a[i]的值 20 printf("%lld\n",ans); 21 } 22 return 0; 23 }