树状数组 进阶篇:区间修改,区间查询

单点更新,区间查询

我们知道,树状数组最基本的功能是 单点更新,区间查询

代码如下:

int lowbit(int x)
{
    return x & (-x);
}
void add(int x, int val)
{
    while (x <= n)
    {
        tree[x] += val;
        x += lowbit(x);
    }
}
int ask(int x)
{
    int res = 0;
    while (x)
    {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}

区间更新,单点查询

通过 “单点更新,区间查询” 功能+差分的思想,我们实现了: 区间更新,单点查询

,所以,以c[i] 建立树状数组,

因为

所以我们想让区间 每一个a[i] 都加上x的话,我们只需要

进入我们今天的主题 :区间更新,区间查询

我们知道数组a[i]的差分数组 c[i] 满足:

那么

于是我们可以用2个树状数组,分别维护 ,数组名分别叫tree1,tree2

区间 的sum和就等于

如果怕询问 等情况,可以第二个树状数组tree2维护,根据差分数组的思想,并不影响结果。

代码:

long long tree1[maxn];
long long tree2[maxn];

long long ask(long long *tree, long long x) {
    long long sum = 0;
    for (; x; x -= (x & -x)) {
        sum += tree[x];
        sum %= mod;
    }
    return sum;
}

void add(long long *tree, long long x, long long y) {
    for (; x <= n; x += (x & -x))
    {
        tree[x] += y;
        tree[x] %= mod;
    }
}

ll query(ll l, ll r)
{
    long long  ans = 0;
    ans = ( (r + 1) * ask(tree1, r) - ask(tree2, r) ) -(  l * ask(tree1, l - 1)  - ask(tree2, l - 1) );
    return ans;
}
void op(ll l, ll r , ll x)
{
    add(tree1, l, x);
    add(tree1, r + 1, -x);
    add(tree2, l, l * x);
    add(tree2, r + 1, -(r + 1) * x);
}