题目描述
结果
- 建立线段树O(logn * n) 查找O(logn) 利用前缀和 回溯计算每个区间的和 求解区间和
- 区间修改需要用[lazy标记]
#include <iostream>
using namespace std;
struct node {
int l, r, cnt;
long long sum, lazy;
};
node tree[40005];
int n, m, num[10005];
inline void backtracking(int now) {
tree[now].sum = tree[now * 2].sum + tree[now * 2 + 1].sum;
}
void builtTree(int now, int l, int r) {
tree[now].l = l;
tree[now].r = r;
tree[now].cnt = r - l + 1;
tree[now].lazy = 0;
if (l == r) {
tree[now].sum = num[l];
return ;
}
int mid = (l + r) / 2;
builtTree(now * 2, l, mid);
builtTree(now * 2 + 1, mid + 1, r);
backtracking(now);
}
void down_lazy(int now) {
if (tree[now].lazy) {
tree[now * 2].sum += tree[now * 2].cnt * tree[now].lazy;
tree[now * 2 + 1].sum += tree[now * 2 + 1].cnt * tree[now].lazy;
tree[now * 2].lazy += tree[now].lazy;
tree[now * 2 + 1].lazy += tree[now].lazy;
tree[now].lazy = 0;
}
}
void modify(int now, int l, int r, int v) {
if (tree[now].l >= l && tree[now].r <= r) {
tree[now].sum += (long long)tree[now].cnt * v;
tree[now].lazy += v;
return ;
}
down_lazy(now);
int mid = (tree[now].l + tree[now].r) / 2;
if (mid >= l) modify(now * 2, l, r, v);
if (mid < r) modify(now * 2 + 1, l, r, v);
backtracking(now);
}
long long query(int now, int l, int r) {
if (tree[now].l >= l && tree[now].r <= r)
return tree[now].sum;
down_lazy(now);
int mid = (tree[now].l + tree[now].r) / 2;
long long t = 0;
if (mid >= l) t += query(now * 2, l, r);
if (mid < r) t += query(now * 2 + 1, l, r);
return t;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &num[i]);
builtTree(1, 1, n);
for (int i = 0; i < m; ++i) {
int t, a, b, c;
scanf("%d", &t);
if (1 == t) {
scanf("%d%d%d", &a, &b, &c);
modify(1, a, b, c);
}
else {
scanf("%d%d", &a, &b);
printf("%lld", query(1, a, b));
}
}
return 0;
}