树状数组
用差分维护序列后,求一个数的值d[p]为
∑
i
=
1
p
b
[
i
]
\sum_{i=1}^{p}b[i]
∑i=1pb[i],求一个区间的值(1~p)为
∑
i
=
1
p
∑
j
=
1
i
b
[
j
]
\sum_{i=1}^{p}\sum_{j=1}^{i}b[j]
∑i=1p∑j=1ib[j] ,将其化简,得到
∑
i
=
1
p
(
p
−
i
+
1
)
∗
b
[
i
]
\sum_{i=1}^{p}(p-i+1)*b[i]
∑i=1p(p−i+1)∗b[i],->
(
p
+
1
)
∗
∑
i
=
1
p
b
[
i
]
−
∑
i
=
1
p
(
b
[
i
]
∗
i
)
(p+1)*\sum_{i=1}^{p}b[i]-\sum_{i=1}^{p}(b[i]*i)
(p+1)∗∑i=1pb[i]−∑i=1p(b[i]∗i)
所以只需要维护b[i] 和 b[i]*i的值就行。
具体代码:
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
#define lowbit(x) (x&-x)
typedef long long ll;
ll c1[N],c2[N],a;
int n,m;
void update(int x,ll v){
for(int i=x;i<=n;i+=lowbit(i)) c1[i] += v,c2[i] += x*v;
}
ll ask(int x){
ll res = 0;
for(int i=x;i;i-=lowbit(i)) res += (x+1)*c1[i] - c2[i];
return res;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a,update(i,a),update(i+1,-a);
while(m --){
char s; int x,y; cin>>s>>x>>y;
if(s == 'C'){
ll d; cin>>d;
update(x,d);
update(y+1,-d);
}else cout<<(ask(y) - ask(x-1))<<endl;
}
return 0;
}
线段树带懒标记:
用一个标记add,表示当前节点区间值被修改,但是子区间未被修改。同样在该线段被完全覆盖的时候返回。递归的时候,每次从上往下传递,判断当前的p是否被标记,是就将其传递给子区间。update和ask都要调用push_down函数处理上往下传递的信息。
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
#define l(x) t[x].l
#define r(x) t[x].r
#define sum(x) t[x].sum
#define add(x) t[x].add
struct SegmenTree{
int l,r;
ll sum,add;
}t[N*4];
int a[N],n,m;
void push_up(int p){
sum(p) = sum(p*2) + sum(p*2+1);
}
void push_down(int p){
if(add(p)){
sum(p*2) += (r(p*2)-l(p*2)+1)*add(p);
sum(p*2+1) += (r(p*2+1)-l(p*2+1)+1)*add(p);
add(p*2) += add(p);
add(p*2+1) += add(p);
add(p) = 0;
}
}
void build(int p,int l,int r){
l(p) = l,r(p) = r;
if(l == r){
sum(p) = a[l];
return ;
}
int mid = (l + r) >> 1;
build(p*2,l,mid);build(p*2+1,mid+1,r);
push_up(p);
}
void update(int p,int l,int r,ll d){
if(l <= l(p) && r >= r(p)){
sum(p) += d*(r(p)-l(p)+1);
add(p) += d;
return ;
}
push_down(p);
int mid = (l(p) + r(p)) >> 1;
if(l <= mid) update(p*2,l,r,d);
if(r > mid) update(p*2+1,l,r,d);
push_up(p);
}
ll ask(int p,int l,int r){
if(l <= l(p) && r >= r(p)) return sum(p);
push_down(p);
int mid = (l(p) + r(p)) >> 1;
ll val = 0;
if(l <= mid) val += ask(p*2,l,r);
if(r > mid) val += ask(p*2+1,l,r);
return val;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,1,n);
while(m --){
char s; int x,y; cin>>s>>x>>y;
if(s == 'C'){
ll d; cin>>d;
update(1,x,y,d);
}else cout<<ask(1,x,y)<<endl;
}
return 0;
}