最近在学线段树,感觉光做题收获并不是很大,还是要静下来归纳总结写写博客缕清思路。
这是一道线段树区间修改,区间求和的裸题的裸题,参照挑战程序设计书上的方法,维护了一个datb[]数组和一个data[]数据,用来记录整个区间增加的值,从而就没必要把add分配给其孩子结点,节省了一大笔开销。
data 和 datb的主要区别在于修改的区间:[a,b] 是否完全包含当前区间[l,r]。若[l,r] 包含于[a,b] ,那只需 data[] += add , 若[l,r] 不完全包含于[a,b], 那么datb[] += (两个区间的交集)*add。
简而言之: data[k] 记录的是当前区间k是否完整的被加过值。
datb[k]记录的是当前区间部分被加过的值,即当前区间无法执行data[k]+=add时使用datb。
加了datb[k] 就解放了data[k],就使data[k] 的定义从结点k对应区间中所有数之和 转变为 如果只执行结点k及其子孙结点中的add操作,结点k对应区间中所有数之和。
当需要求和的时候,若[a,b]没有完全包含[l,r],则res = [l,r]与[a,b]交集的长度data[k],需要加上之前结点k累计的部分add值,即res = data[k] (当前区间与目标区间的交集),此时不加datb[k]的原因是当前区间并未完全包含于[a,b],datb[k]代表的是当前区间某部分的add值。
所以只有到[l,r]完全包含于[a,b]时,才可以执行 return data[k] *(r-l)+datb[k]。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
#define fre freopen("/Users/user/Desktop/in.txt","r",stdin);
#define CLR(s) memset(s,0,sizeof(s));
#define lson l, (l+r)/2
#define rson (l+r)/2 , r
typedef long long ll;
const int DAT_SIZE = (1<<18)-1;
const int MAX_N = 100000+10;
const int MAX_Q = 100000+10;
int N,Q,A[MAX_N],L[MAX_Q], R[MAX_Q], X[MAX_Q];
char T[MAX_Q];
ll data[DAT_SIZE], datb[DAT_SIZE];
void add(int a,int b, int x, int k, int l,int r){
if(a <= l && r <= b) // [l,r]包含于[a,b]
data[k] += x;
else if(l < b && a < r){
datb[k] += (min(b,r) - max(a,l))*x; // [a,b] 与 [l,r]相交的区间
add(a,b,x,k*2+1,lson);
add(a,b,x,k*2+2,rson);
}
}
ll sum(int a, int b, int k, int l,int r){
if(b <= l || r <= a)
return 0;
else if(a <= l && r <= b) // [l,r]包含于[a,b]
return data[k]*(r-l)+datb[k]; // 加上当前结点全部的add值,并且加上之前add操作中对此结点部分区间进行add的值
else{
ll res = (min(b,r)-max(a,l))*data[k]; // 加上当前结点交集中的add值,datb先不加。
res += sum(a,b,k*2+1,lson);
res += sum(a,b,k*2+2,rson);
return res;
}
}
void solve(){
for(int i = 0; i < N; ++i)
add(i,i+1, A[i], 0,0,N);
for(int i = 0; i < Q; ++i)
if(T[i] == 'C')
add(L[i],R[i]+1,X[i],0,0,N);
else
printf("%lld\n", sum(L[i],R[i]+1,0,0,N));
}
int main(){
cin >> N >> Q;
for(int i = 0; i < N; ++i)
cin >> A[i];
for(int i = 0; i < Q; ++i){
cin >> T[i];
if(T[i] == 'Q')
cin >> L[i] >> R[i];
else
cin >> L[i] >> R[i] >> X[i];
L[i]--; R[i]--;
}
solve();
return 0;
}