树状数组区间修改区间查询

相关题目链接

  • 线段树1

    Solution

  • 首先看到题目标题,我们就知道要用线段树,但这道题还可以用其他方法来AC,比如树状数组,不仅代码量少,而且常数还小,根据树状数组模板2我们知道,树状数组的区间修改是要用差分的,这点我的另一篇Blog介绍过,不懂的点击
  • 接下来我们直接将如果用树状数组实现区间修改区间查询。我们用a数组表示原序列,d数组表示差分数组,我们可得 $\sum\limits_{i=1}^{p}a[i]=\sum\limits_{i=1}^{p}\sum\limits_{j=1}^{i}d[j]$ ,在右侧的式子中,$d[1]$被用了$p$次,$d[2]$被用了$p-1$次,我们可以推出位置p的前缀和
    ,我们可以维护两个数组前缀和$sum1[i]=d[i]$,另一个数组$sum2[i]=d[i]*i$
  • 查询
    位置$p$的前缀和即: $(p + 1) * sum1$数组中$p$的前缀和- sum2数组中p的前缀和。区间[l, r]的和即:位置r的前缀和 - 位置l的前缀和。
  • 修改
    对于sum1数组的修改同问题2中对$d$数组的修改。

    对于sum2数组的修改也类似,我们给 sum2[l] 加上 $l \times x$ ,给 sum2[r + 1] 减去
    $(r + 1) \times x$。

    Code

    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
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define gc getchar()
    #define pc(x) putchar(x)
    typedef long long ll;
    const int Maxn = 100000 + 10;
    ll sc() {
    ll xx = 0, ff = 1; char cch = gc;
    while(!isdigit(cch)) {
    if(cch == '-') ff = -1; cch = gc;
    }
    while(isdigit(cch)) {
    xx = (xx << 1) + (xx << 3) + (cch ^ '0'); cch = gc;
    }
    return xx * ff;
    }
    void out(ll x) {
    if(x < 0) pc('-'), x = -x;
    if(x >= 10)
    out(x / 10);
    pc(x % 10 + '0');
    }
    ll n, m;
    ll sum1[Maxn], sum2[Maxn];
    ll lowbit(ll x) {
    return x & (-x);
    }
    void modify(ll x, ll num) {
    for(int i = x; i <= n; i += lowbit(i))
    sum1[i] += num, sum2[i] += num * x;
    }
    void update(ll x, ll y, ll num) {
    modify(x, num);
    modify(y + 1, -num);
    }
    ll ask(ll x) {
    ll ans = 0;
    for(int i = x; i; i -= lowbit(i))
    ans += (x + 1) * sum1[i] - sum2[i];
    return ans;
    }
    ll query(ll x, ll y) {
    return ask(y) - ask(x - 1);
    }
    int main() {
    n = sc(); m = sc();
    for(int i = 1; i <= n; ++i)
    update(i, i, sc());
    while(m--) {
    ll flag = sc(), x = sc(), y = sc();
    if(flag == 1) {
    ll num = sc();
    update(x, y, num);
    }
    else {
    out(query(x, y)), pc('\n');
    }
    }
    return 0;
    }
    // Coded by dy.

rp++*