> 啥是分块? 算法
简单的说, 就是给你一段长度为 n 序列, 把它分红 x 叉树的形式(每层有 x 个块), 能够分红 logx(n) 层; 数组
若是采用 sqrt(n) 叉树, 就有 2 层; 若是采用 2 叉树, 就有 logn 层; 优化
第一个是分块, 第二个是线段树. spa
> 为何要分块? 3d
有 x 次操做, 每次操做复杂度为 O(a), 有 y 次询问, 每次询问复杂度为 O(b), 咱们就能够经过提升一边的复杂度来下降另外一边的复杂度, 使总体复杂度平衡, 以提高整个算法的效率. blog
举个例子, 给出一个序列, 进行 m 次操做: 修改某个位置的值, 查询某段区间的和. 排序
若是直接作, 修改是 O(1) 的复杂度, 查询是 O(n) 的, 总体复杂度就是 O(m*n), 但咱们利用线段树平衡两边的复杂度, 使修改与查询都为 O(logn), 整个算法的复杂度就是 O(mlogn) 了. get
分块也同理, 平衡两边复杂度为 O(sqrt(n)), 这个过程称做根号平衡, 因此根号算法的复杂度就是 O(m*sqrt(n)). io
> 分块解决什么问题? 效率
例1: 维护一个长度为 n 的序列, 进行 m 次操做: 区间加, 查询某段区间内小于 x 的数的个数.
若是是单点修改, 咱们能够用树套树来实现, 但区间修改树套树没法快速合并信息.
若是信息能够快速合并, 则优先选择线段树结构, 毕竟 logn 是优于 sqrtn 的; 而对于没法快速合并信息的状况, 就能够考虑用分块实现.
这道题, 分块并将每块排序. 修改时, 整块打标记, 零散块枚举 + 重构(重构用归并); 查询时, 整块查询小于 x 的数, 这个整块的标记为 y(也就是说这一块全部数都加了y)则等价于查整块的排序后的数组里面小于 x - y 的数的个数, 查找能够二分, 零散块就直接暴力查询块内在查询区间内的数是否知足条件.
例2: 维护一个长度为 n 的序列, 进行 m 次操做: 区间加, 查询某段区间内第 k 小的数.
解法与例1相似. 查询第 k 小的数时, 须要二分答案, 而后在每一个整块上用 lower_bound()求有多少个数比二分出的这个答案小, 在零散块上枚举, 累加起来, 看是否是等于 k-1. So easy?
诶, 等等, 每二分一个答案, 就枚举一遍零散块, 这样不是很慢么? 这样复杂度 O(logn * sqrtn)的呀.
想办法优化这个复杂度. 咱们能够把零散块归并成一个假的整块, 在这个整块上 lower_bound(), 这样复杂度就是 O(sqrtn + logn * log(sqrtn))了.
例3: 维护一个序列, 支持 O(1)单点修改, O(sqrt(n))区间和.
分块维护序列. 直接修改原数组和所在的块, 查询整块 O(1), 零散块 O(sqrt(n))枚举.
例4: 维护一个序列, 支持 O(sqrt(n))单点修改, O(1)区间和.
分块维护前缀和. 维护块内序列的前缀和, 维护块的前缀和. 修改当前块内前缀和与块的前缀和, 查询整块的块前缀和与零散块的块内前缀和.
例5: 维护一个序列, 支持 O(sqrt(n))区间加, O(1)查单点.
分块维护序列. O(1)加整块, O(sqrt(n))枚举加零散块, O(1)查询.
例6: 维护一个序列, 支持 O(1)区间加, O(sqrt(n))查单点.
差分. 把 a[i]变为 a[i] - a[i-1], 区间加至关于修改单点, 查询单点至关于求前缀和, 转变成例5.
例7: 维护一个集合, 支持 O(1)插入一个数, O(sqrt(n))查询第 k 小.
离散化后分块维护值域. a[i]表示数字 i 出现的次数, 维护每一个块内有多少个数. 查询的时候从第一个块开始往右跑, 最多走过 sqrt(n)个整块和 sqrt(n)个零散的数.
例8: 维护一个集合, 支持 O(sqrt(n))插入一个数, O(1)查询第 k 小.
这个题比较有意思, 能够先想想再看.
考虑到要 O(1)查询, 可见确定要能直接定位到第 k 小的数的位置.
先离线读入全部的操做, 把插入的数放在一个序列里面, 将序列排序后分块.
用 pos[i]记录元素 i 在哪一个块中, 若是 i 有多个则记录第一个.
用 L[i]和 R[i]分别记录第 i 个块的左右端点, 即第 i 个块里面是排名 L[i] ~ R[i]的数.
用 belong[i]表示排名第 i 的数在哪一个块里.
每插入一个数 i, 就把它放到 pos[i]这个块的尾部, O(sqrt(n))维护一下块内的大小顺序, O(sqrt(n))维护一下后面块的左右端点(由于日后移了一位).
询问时, 输出 Block[belong[k]][k - L[belong[k]]].
更多题目参见标签 "分块", "题解", 不断更新.