题意:
给出点集数以及命令数;
先将每一个点赋初值
Q a b 表示求出点集中从a到b的和
C a b c 表示将a到b的点全部加c
解析:
线段树,并且单纯的线段树会超时,因为在将a到b的点全部加上c时,步骤太多,会超时。需要优化。即Lazy算法;
Lazy算法:
在将 ql ~ qr 点全部加 val 时,不要加到每个点,在表示区间的 root 结构体上增加一个addv域,将要加的值赋给这个addv域,然后就不要再往下了。在求区间和时,将root中的 addv 值赋给要求的区间,并且将该节点的root置零。
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define ls o*2
#define rs o*2+1
using namespace std;
typedef __int64 ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
ll addv[N<<2], sumv[N<<2], a[N];
inline void maintain(int o, int L, int R) {
sumv[o] = 0;
if(R > L) {
sumv[o] = sumv[ls] + sumv[rs];
}
sumv[o] += addv[o] * (R-L+1);
}
void build(int o, int L, int R) {
if(L == R) {
sumv[o] = addv[o] = a[L];
return ;
}
int M = (L+R)/2;
build(ls, L, M);
build(rs, M+1, R);
maintain(o, L, R);
}
int ql, qr, val;
void modify(int o, int L, int R) {
if(ql <= L && R <= qr) {
addv[o] += val;
}else {
int M = (L+R)/2;
if(ql <= M) modify(ls, L, M);
if(qr > M) modify(rs, M+1, R);
}
maintain(o, L, R);
}
ll _sum;
void query(int o, int L, int R, ll add) {
if(ql <= L && R <= qr) {
_sum += sumv[o] + add*(R-L+1);
}else {
int M = (L+R)/2;
if(ql <= M) query(ls, L, M, add+addv[o]);
if(qr > M) query(rs, M+1, R, add+addv[o]);
}
}
int main() {
int n, q;
char cmd[4];
while(scanf("%d%d", &n, &q) != EOF) {
for(int i = 1; i <= n; i++)
scanf("%I64d", &a[i]);
build(1, 1, n);
while(q--) {
scanf("%s", cmd);
if(cmd[0] == 'Q') {
scanf("%d%d", &ql, &qr);
_sum = 0;
query(1, 1, n, 0);
printf("%I64d\n", _sum);
}else if(cmd[0] == 'C') {
scanf("%d%d%d", &ql, &qr, &val);
modify(1, 1, n);
}
}
}
return 0;
}