• 树状数组及其简单扩展


    树状数组及其简单扩展

    不对树状数组做详细讲解,只对应用类型做总结.

    一维树状数组

    单点修改,区间查询

    由于树状数组维护的是前缀信息,所以区间查询直接利用前缀特性相减即可.
    单点修改只需从开始位置向后更新即可.

    区间修改,单点查询

    树状数组只支持单点修改,那么如何处理区间修改呢?
    考虑常见的区间修改转单点修改的套路:差分.
    而差分数组的前 (n) 项和也恰好就是真正的 (v_i).
    所有直接差分去做即可.

    区间修改,区间查询

    同理,先差分,差分后区间修改是没有区别的.
    而这里我们发现,我们只能得到对应的单点值,却不能直接得到对应的区间和.
    难道要套一种可以区间求和的数据结构嘛?答案是否定的.
    我们发现,我们要求的其实是这个:

    [sum_{i=l}^r{sum_{j=1}^i}{d_j} ]

    其中,(d_j) 就是差分数组.对于内层求和显然可以直接在树状数组中查询得到.
    那么怎么处理外层呢?再 (for) 一遍是显然不可能的.
    所以我们重新考虑:
    (sum_i) 表示前缀和.

    [egin{array}{c}{operatorname{sum}[i]=sum_{j=1}^{i} operatorname{d}[j] *(i-j+1)} \ {operatorname{sum}[i]=(i+1) * sum_{j=1}^{i}d[j]-sum_{j=1}^{i}d[j] * j}end{array} ]

    所以只需要去维护一个原数组的前缀和,一个和之前一样的树状数组,和另一个维护(d_j imes j) 的树状数组即可.

    二维树状数组

    单点修改,矩阵查询

    直接单点去修改,二维前缀和形式查询即可.

    矩阵修改,单点查询

    二维差分后,每次矩阵修改只需要在四个位置修改即可.

    单点查询直接用二维树状数组求二维前缀和即可.

    矩阵修改,矩阵查询

    同样还是先二维差分,矩阵修改就直接在四个位置单点修改即可.

    那么矩阵查询呢?我们又遇到了和上面同样的问题.

    这次我们要求的式子变成了这样:

    [sum_{i=1}^{n}sum_{j=1}^{m}sum_{i=k}^{n}sum_{j=l}^{m}{d_{k,l}} ]

    枚举次序转换一下得到:

    [sum_{k=1}^{n}sum_{l=1}^{m}sum_{i=k}^{n}sum_{j=l}^{m}d_{k,l} ]

    此时,(d_{k,l})(i,j) 无关,所以上式可写成:

    [sum_{k=1}^{n}sum_{l=1}^{m}{d_{k,l} imes (n-k+1) imes (m-l+1)} ]

    出于习惯,把它写作:

    [sum_{i=1}^{n}sum_{j=1}^{m}{d_{i,j} imes (n-i+1) imes (m-j+1)} ]

    考虑拆项,得到:

    [left(sum_{i=1}^{n} sum_{j=1}^{m} d_{i, j} ight) imes(n+1) imes (m+1)-sum_{i=1}^{n} sum_{j=1}^{m} i imes d_{i, j} imes(m+1)-sum_{i=1}^{n} sum_{j=1}^{m} j imes d_{i, j} imes(n+1)+sum_{i=1}^{n} sum_{j=1}^{m} i imes j imes d_{i, j} ]

    于是,和上面的一维情况类似,维护四个不同的树状数组即可.

    Summary

    虽然有句话叫:树状数组能实现的所有操作,线段树都可以实现.
    但很多时候还是树状数组更为简便,高效.
    树状数组有着线段树无法比拟的高效率和低代码难度,树状数组的唯一缺点就是有些操作树状数组不能或者难以维护.
    例如一维和二维情况下的区间最值问题,如果硬要用树状数组去实现,那么会多出一个 (log) 的复杂度,二维情况会多出两个 (log) 的复杂度来.

    所以,能使用树状数组的情况下,不去使用线段树是一个明智的选择,毕竟树状数组的时空复杂度都要优于线段树.(除区间最值这类问题以外

  • 相关阅读:
    va_list/va_start/va_arg/va_end深入分析【转】
    Linux Kernel中断子系统来龙去脉浅析【转】
    Linux系统调用---同步IO: sync、fsync与fdatasync【转】
    Linux中变量#,#,@,0,0,1,2,2,*,$$,$?的含义【转】
    linux下的module_param()解释【转】
    Makefile 使用总结【转】
    FLASH的知识【转】
    Linux MTD系统剖析【转】
    linux的mtd架构分析【转】
    linux设备树笔记__dts基本概念及语法【转】
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/11668498.html
Copyright © 2020-2023  润新知