1. tag中存储的是左右子树中stree的待加的单位值,也就是说当一个节点他的祖先tag全为0时,我们保证它的stree值是准确的。
  2. 除此之外pushdown/update的时机需要注意,一个是在query/edit中对左右子树递归之前进行pushdown,另一个是add区间左右子树都递归的add之后回溯的时候update。据此,我们可以得出,每次add之后,所有被新打上tag的节点的祖先都会被pushdown一次,tag会被清空。
  3. 注意pushdown中判断l != r,否则会引发RE
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define lson(x) (x << 1)
    #define rson(x) (x << 1 | 1)
    #define update(x) (stree[x] = stree[x << 1] + stree[x << 1 | 1])
    #define mid(l, r) ((l + r) >> 1)
    using namespace std;
    typedef long long ll;
    int n;
    int q;
    ll stree[1000007];
    ll tag[1000007];
    ll raw[1000007];
    void build(int root, int l, int r) {
    if (l == r) {
    stree[root] = raw[l];
    return;
    }
    build(lson(root), l, mid(l, r));
    build(rson(root), mid(l, r) + 1, r);
    update(root);
    }
    void pushdown(int root, int l, int r) {
    if (l == r) return;
    if (tag[root]) {
    tag[lson(root)] += tag[root];
    tag[rson(root)] += tag[root];
    stree[lson(root)] += tag[root] * (mid(l, r) - l + 1);
    stree[rson(root)] += tag[root] * (r - mid(l, r));
    tag[root] = 0;
    }
    // update(root);
    }
    ll query(int root, int l, int r, int ql, int qr) {
    if (l > qr || r < ql) return 0;
    if (l >= ql && r<= qr) return stree[root];
    pushdown(root, l, r);
    return query(lson(root), l, mid(l, r), ql, qr) +
    query(rson(root), mid(l, r) + 1, r, ql, qr);
    }
    void add(int root, int l, int r, int al, int ar, ll dataadd) {
    if (l > ar || r < al) return;
    if (l >= al && r <= ar) {
    tag[root] += dataadd;
    stree[root] += (r - l + 1) * dataadd;
    return;
    }
    pushdown(root, l, r);
    add(lson(root), l, mid(l, r), al, ar, dataadd);
    add(rson(root), mid(l, r) + 1, r, al, ar, dataadd);
    update(root);
    }
    int main() {
    int a, b, x, y;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
    scanf("%lld", raw + i);
    }
    build(1, 1, n);
    scanf("%d", &q);
    while (q--) {
    scanf("%d %d %d", &x, &a, &b);
    if (x == 1) {
    scanf("%d", &y);
    add(1, 1, n, a, b, y);
    } else {
    printf("%lld\n", query(1, 1, n, a, b));
    }
    }
    return 0;
    }