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


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

    单点更新,区间查询

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

    代码如下:

    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]-a[i-1]),所以,以c[i] 建立树状数组,(a[i]=ask(i))

    因为(a[i]=sum_{j=1}^i c[i])

    所以我们想让区间([l,r]) 每一个a[i] 都加上x的话,我们只需要(add(l,x),add(r+1,-x))

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

    我们知道数组a[i]的差分数组 c[i] 满足:(a[i]=sum_{j=1}^i c[i])

    那么(sum_{i=1}^na[i]=sum_{i=1}^n{sum_{j=1}^ic[i]})

    (sum_{i=1}^na[i]=c[1]+(c[1]+c[2])+(c[1]+c[2]+c[3])+dots+sum_{j=1}^n c[i])

    (sum_{i=1}^na[i]=n*(c[1]+c[2]+c[3]+dots+c[n])-(c[2]+2*c[3]+3*c[4]+dots+(n-1)*c[n]))

    (sum_{i=1}^na[i]=n*(sum_{i=1}^n c[i])- sum_{i=1}^n(i-1)*c[i])

    于是我们可以用2个树状数组,分别维护 (c[i])((i-1)*c[i]),数组名分别叫tree1,tree2

    区间([l,r]) 的sum和就等于(query(r)-query(l-1))

    (query(x)=x*ask(tree1,x)-ask(tree2,x))

    如果怕询问([0,x]) 等情况((i-1)<0),可以第二个树状数组tree2维护((i*c[i])),根据差分数组的思想,并不影响结果。

    代码:

    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);
    }
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    从JavaScript的事件循环到Promise
    Vuex初识
    npm常用命令及版本号浅析
    npm install 时--save-dev和--save的区别
    Json-Server模拟数据接口开发
    基于Express+Socket.io+MongoDB的即时聊天系统的设计与实现
    fileInput实战总结
    找工作总结
    nodejs-基本语法
    初识nodejs
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12301351.html
Copyright © 2020-2023  润新知