Description
Description
设计一种数据结构,支持在一个序列中进行以下两种操作:
C l r k:将序列中第l到第r个数每个加上k。
Q l r:输出当前序列中第l到第r个数的总和
不能用线段树来解,不能用线段树来解,不能用线段树来解!(既然被划掉了我就用itree了)
Input
第一行n,q(1 ≤ n,q ≤ 100000),表示序列中数的个数和操作的个数。
第二行n个数,表示初始序列(-1000000000 ≤ 每个数≤ 1000000000)
第3至2+q行,每行一个操作,意义如题目描述所示。
Output
对于每个Q操作,输出对应的结果,每个一行。
Sample Output
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9
15
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int SIZE = 100010;
ll sum[SIZE<<2], tag[SIZE<<2], a[SIZE];
void pushup(int rt) { // 结果上传
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void build(int rt, int l, int r) { // 建树
if (l==r) {
sum[rt] = a[l]; return;
}
int m = (l+r) >> 1;
build(rt<<1, l, m); build(rt<<1|1, m+1, r);
pushup(rt);
}
void pushdown(int rt, int l, int r) { // 懒标记下传
if (tag[rt]) {
if (l<r) { // 注意不是叶子才左右放懒标记,小心RE
int m = (l+r) >> 1;
tag[rt<<1] += tag[rt]; tag[rt<<1|1] += tag[rt]; // 给儿子放lazytag
sum[rt<<1] += tag[rt] * (m-l+1); sum[rt<<1|1] += tag[rt] * (r-m); // 儿子的计数器增加
}
tag[rt] = 0;
}
}
void update(int rt, int l, int r, int x, int y, ll val) { // 区间修改
if ((x<=l) && (r<=y)) { // 完全包括,放懒标记
tag[rt] += val; sum[rt] += val * (r-l+1); return;
}
pushdown(rt, l, r); // 下传tag
int m = (l+r) >> 1;
if (x<=m) update(rt<<1, l, m, x, y, val);
if (y>m) update(rt<<1|1, m+1, r, x, y, val);
pushup(rt); // 更新
}
ll query(int rt, int l, int r, int x, int y) { // 区间查询
if ((x<=l) && (r<=y)) return sum[rt];
pushdown(rt, l, r); // 下传tag
ll res = 0;
int m = (l+r) >> 1;
if (x<=m) res += query(rt<<1, l, m, x, y);
if (y>m) res += query(rt<<1|1, m+1, r, x, y);
return res;
}
int main(void) {
int n, m;
scanf("%d%d", &n, &m);
for (int i=1; i<=n; ++i) {
scanf("%lld", &a[i]);
}
build(1, 1, n);
while (m--) {
int l, r;
char op[3];
scanf("%s%d%d", op, &l, &r);
if (op[0]=='C') {
ll k;
scanf("%lld", &k);
update(1, 1, n, l, r, k);
}
else {
printf("%lld\n", query(1, 1, n, l, r));
}
}
return 0;
}