洛谷P3372 【模板】线段树 1 【树状数组解法】
这里用树状数组写法;
考虑求[1,x]的区间和 \(sum_x\),于是将原数组差分后,相当于求一个二阶前缀和;
设原数组为 \(a_i\), 差分后的数组为 \(b_i = a_i - a_{i-1}\);
于是 \(a_i = \sum_{j=1}^{i}{b_j}\);
那么[1,x]的区间和为 \(sum_x = \sum_{i=1}^{x}a_i = \sum_{i=1}^{x} \sum_{j=1}^{i}b_j\)
\(sum_x = a_1 + a_2 + \cdots + a_x\)
\(= (b_1) + (b_1+b_2) + (b_1+b_2+b_3) + \cdots + (b_1+b_2+b_3+\cdots+b_x)\)
$= xb_1 + (x-1)b_2 + (x-2)b_3 + \cdots + (x-n+1)b_n + \cdots + b_x $
$= \sum_{n=1}^{x}{(x-n+1)b_n} $
$= (x+1)\sum_{n=1}^{x}b_n - \sum_{n=1}^{x}b_n \cdot n $
于是分别在树状数组上维护 $\sum_{n=1}^{x}b_n $ 与 $ \sum_{n=1}^{x}b_n \cdot n $
$ ans = sum_r - sum_{l-1} $
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define MS 1000009
int n,m;
LL a[MS];
LL b[MS];
LL p[2][MS];
int lowbit(int x){
return x&(-x);
}
void add(int rt, int pos, LL val){
for(;pos<=n;pos+=lowbit(pos)) p[rt][pos] += val;
}
LL query(int pos){
LL cc = 0;
for(LL t=pos+1;pos;pos-=lowbit(pos)) cc += t*p[0][pos]-p[1][pos];
return cc;
}
int main(){
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
}
for(int i=1;i<=n;i++){
b[i] = a[i] - a[i-1];
add(0, i, b[i]);
add(1, i, b[i]*i);
}
while(m--){
LL op,l,r;
cin >> op >> l >> r;
if(op == 1){
LL x;
cin >> x;
add(0, l, x);
add(0, r+1, -x);
add(1, l, x*l);
add(1, r+1, -x*(r+1));
}
else if(op == 2){
LL ans = query(r) - query(l-1);
cout << ans << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号