• 树状数组区间修改,区间更新:差分数组的运用


    树状数组最原始的作用就是求前缀和,可以实现单点修改和区间查询。

    但是假设现在有:

    1.区间修改,单点查询

    2.区间修改,区间查询

    但是又不想敲线段树怎么办?

    就用树状数组喽。

    假设现在有一个原数组a(假设a[0] = 0),有一个数组d,d[i] = a[i] - a[i-1],那么

    a[i] = d[1] + d[2] + .... + d[i]

    d数组就是差分数组

    所以求a[i]就可以用树状数组维护d[i]的前缀和

    区间修改,单点查询:

    根据d的定义,对[l,r]区间加上x,那么a[l]和a[l-1]的差增加了x,a[r+1]与a[r]的差减少了x,所以就对差分数组的前缀和进行修改

    设c是差分数组的前缀和

    区间修改:

    void add(int x,int k)
    {
        for (int i = 1;i <= n;i += lowbit(i)) c[i] += k;
    }
    {
        add(l,x);
        add(r+1,-x);
    }

    单点查询:

    int sum(int x)
    {
        int ans = 0;
        for (int i = x;i > 0;i -= lowbit(i)) ans += c[i];
        return ans;
    }

    区间修改,区间查询:

    根据上面的差分数组的定义可以得到:

    a[1] + a[2] + a[3] + ... + a[k] = d[1] + d[1] + d[2] + d[1] + d[2] + d[3] + ... + d[1] + d[2] + d[3] + ... + d[k]

                  = Σ(k - i + 1) * d[i]  (i从1到k)

    变化一下 Σa[i] (i从1到k) = Σ(k+1) * d[i] - i * d[i] (i从1到k)

    d[i]可以用一个前缀和维护,i * d[i]也可以用一个前缀和进行维护,所以区间修改,区间查询就变得很方便了

    假设c1维护d[i]的前缀和,c2维护d[i] * i的前缀和

    区间修改:

    void add(int x,int y)
    {
        for (int i = x;i <= n;i += lowbit(i)) c1[i] += y,c2[i] += x * y;
    }
    {
        add(l,x);
        add(r+1,-x);
    }

    区间查询:

    int sum(int x)
    {
        int ans1 = 0;
        int ans2 = 0;
        for (int i = x;i > 0;i -= lowbit(i))
        {
            ans1 += (x + 1) * c1[i];
            ans2 += c2[i];
        }
        return ans1 - ans2;
    }

    比线段树好写多了(蓝儿还是容易写炸

    参考了以下两位前辈的博客,感谢:

    https://www.cnblogs.com/lcf-2000/p/5866170.html

    https://www.cnblogs.com/RabbitHu/p/BIT.html

  • 相关阅读:
    python 快速排序详述
    GitHub 小试牛刀(踩坑记录)
    python 内部类
    Django1.11搭建一个简易上传显示图片的后台
    Ubuntu16.04卸载opencv2.4.9并安装opencv3.2.0+contrib
    OpenCV4Android背景建模(MOG、MOG2)
    CentOS7.3安装NVIDIA-1080ti驱动、cuda、cudnn、TensorFlow
    TensorFlow Object Detection API(Windows下测试)
    关于git常见的一些问题
    聊聊Java中的反射(一)
  • 原文地址:https://www.cnblogs.com/kickit/p/9172189.html
Copyright © 2020-2023  润新知