标记永久化线段树 区间更新求和
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int MAXN = 100009; int n, q; ll sum[MAXN * 4], add[MAXN * 4]; void build(int l, int r, int rt) { add[rt] = 0; if (l == r) { scanf("%lld", &sum[rt]); return; } int mid = (l + r) >> 1; build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1); sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]); } void update(int l, int r, int rt, int ql, int qr, int c) { sum[rt] += c * (qr - ql + 1); if (l == ql && r == qr) { add[rt] += c; return; } int mid = (l + r) >> 1; if (qr <= mid) update(l, mid, rt << 1, ql, qr, c); else if (ql > mid) update(mid + 1, r, rt << 1 | 1, ql, qr, c); else { update(l, mid, rt << 1, ql, mid, c); update(mid + 1, r, rt << 1 | 1, mid + 1, qr, c); } } ll query(int l, int r, int rt, int ql, int qr, ll c) { if (l == ql && r == qr) return sum[rt] + c * (r - l + 1); int mid = (l + r) >> 1; if (qr <= mid) return query(l, mid, rt << 1, ql, qr, c + add[rt]); else if (ql > mid) return query(mid + 1, r, rt << 1 | 1, ql, qr, c + add[rt]); else return query(l, mid, rt << 1, ql, mid, c + add[rt]) + query(mid + 1, r, rt << 1 | 1, mid + 1, qr, c + add[rt]); } int main() { scanf("%d %d", &n, &q); build(1, n, 1); char ch[2]; int x, y, z; while (q--) { scanf("%s", ch); if (ch[0] == 'Q') { scanf("%d %d", &x, &y); printf("%lld\n", query(1, n, 1, x, y, 0)); } else { scanf("%d %d %d", &x, &y, &z); update(1, n, 1, x, y, z); } } return 0; }