牛客小白月赛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
",ans);
21     }
22     return 0;
23 }
原文地址:https://www.cnblogs.com/acgoto/p/9470316.html