这是一道模板题。
给定数列 a[1],a[2],…,a[n]a[1],a[2],…,a[n],你需要依次进行 qq 个操作,操作有两类:
1 l r x
:给定 l,r,xl,r,x,对于所有 i∈[l,r]i∈[l,r],将 a[i]a[i] 加上 xx(换言之,将 a[l],a[l+1],…,a[r]a[l],a[l+1],…,a[r] 分别加上 xx);2 l r
:给定 l,rl,r,求 ∑ri=la[i]∑i=lra[i] 的值(换言之,求 a[l]+a[l+1]+?+a[r]a[l]+a[l+1]+?+a[r] 的值)。
Input
第一行包含 22 个正整数 n,qn,q,表示数列长度和询问个数。保证 1≤n,q≤1061≤n,q≤106。
第二行 nn 个整数 a[1],a[2],…,a[n]a[1],a[2],…,a[n],表示初始数列。保证 |a[i]|≤106|a[i]|≤106。
接下来 qq 行,每行一个操作,为以下两种之一:
1 l r x
:对于所有 i∈[l,r]i∈[l,r],将 a[i]a[i] 加上 xx;2 l r
:输出 ∑ri=la[i]∑i=lra[i] 的值。
保证 1≤l≤r≤n,1≤l≤r≤n, |x|≤106|x|≤106。
Output
对于每个 2 l r
操作,输出一行,每行有一个整数,表示所求的结果。
样例输入
5 10
2 6 6 1 1
2 1 4
1 2 5 10
2 1 3
2 2 3
1 2 2 8
1 2 3 7
1 4 4 10
2 1 2
1 4 5 6
2 3 4
样例输出
15
34
32
33
50
思路:区间修改+区间查询;感谢https://www.cnblogs.com/kickit/p/9172189.html
LL c[maxa];//前缀和
LL c1[maxa],c2[maxa];//c1维护d[i]的前缀和,c2维护d[i] * i的前缀和
void add(LL x,LL y){//更新 for(LL i=x;i<=n;i+=lowbit(i)) c1[i]+=y,c2[i]+=x*y;
}
LL sum(LL x){LL ans1=0;LL ans2=0;for(LL i=x;i>0;i-=lowbit(i)){ans1+=(x+1)*c1[i];ans2+=c2[i];}return ans1-ans2;
}
完整代码如下:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<cstdio>
#define LL long long
using namespace std;
const int maxa=1e6+10;
LL n,q;
LL c[maxa];//前缀和
LL c1[maxa],c2[maxa];//c1维护d[i]的前缀和,c2维护d[i] * i的前缀和
LL lowbit(LL i){return (i&-i);
}
void add(LL x,LL y){//更新 for(LL i=x;i<=n;i+=lowbit(i)) c1[i]+=y,c2[i]+=x*y;
}
LL sum(LL x){LL ans1=0;LL ans2=0;for(LL i=x;i>0;i-=lowbit(i)){ans1+=(x+1)*c1[i];ans2+=c2[i];}return ans1-ans2;
}
int main(){LL c,b=0;scanf("%lld",&n);scanf("%lld",&q);for(int i=1;i<=n;i++){scanf("%lld",&c);add(i,c-b);b=c;} LL op,e1,e2,e3;for(int i=0;i<q;i++){scanf("%lld",&op);if(op==1){scanf("%lld",&e1);scanf("%lld",&e2);scanf("%lld",&e3); if(e1>e2) swap(e1,e2);add(e1,e3);add(e2+1,-e3);}else{scanf("%lld%lld",&e1,&e2);printf("%lld\n",sum(e2)-sum(e1-1));}}return 0;
}