第一次写区间修改的线段树。
update(): 成段增减
query(): 区间求和
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn = 110000;
LL sum[maxn<<2];
LL add[maxn<<2];
void pushUp(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushDown(int rt, int l, int r)
{
int m = r-l+1;
if(add[rt]) {
add[rt<<1] += add[rt];
sum[rt<<1] += add[rt] * (m-(m>>1));
add[rt<<1|1] += add[rt];
sum[rt<<1|1] += add[rt] * (m>>1);
add[rt] = 0;
}
}
void build(int rt, int l, int r)
{
add[rt] = 0;
if(l == r) {
scanf("%lld", &sum[rt]);
return ;
}
int m = (l+r)>>1;
build(rt<<1, l, m);
build(rt<<1|1, m+1, r);
pushUp(rt);
}
void update(int L, int R, LL c, int rt, int l, int r)
{
if(L <= l && r <= R) {
add[rt] += c;
sum[rt] += c * (r-l+1);
return ;
}
pushDown(rt, l, r);
int m = (l+r)>>1;
if(L <= m) update(L, R, c, rt<<1, l, m);
if(R > m) update(L, R, c, rt<<1|1, m+1, r);
pushUp(rt);
}
LL Query(int L, int R, int rt, int l, int r)
{
if(L <= l && r <= R)
return sum[rt];
pushDown(rt, l, r);
LL ret = 0;
int m = (l+r)>>1;
if(L <= m) ret += Query(L, R, rt<<1, l, m);
if(R > m) ret += Query(L, R, rt<<1|1, m+1, r);
return ret;
}
int main()
{
int n, q;
while(~scanf("%d%d", &n, &q)) {
build(1, 1, n);
for(int i = 0; i < q; i++) {
char cmd[2];
scanf("%s", cmd);
if(cmd[0] == 'C') {
int a, b;
LL c;
scanf("%d%d%lld", &a, &b, &c);
update(a, b, c, 1, 1, n);
}
else {
int a, b;
scanf("%d%d", &a, &b);
printf("%lld\n", Query(a, b, 1, 1, n));
}
}
}
return 0;
}