ACM入门之分块
Posted 辉小歌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM入门之分块相关的知识,希望对你有一定的参考价值。
分块是一种思想,而不是一种数据结构。
分块的基本思想是,通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。
分块的时间复杂度主要取决于分块的块长,一般可以通过均值不等式求出某个问题下的最优块长,以及相应的时间复杂度。
分块是一种很灵活的思想,相较于树状数组和线段树,分块的优点是通用性更好,可以维护很多树状数组和线段树无法维护的信息。
当然,分块的缺点是渐进意义的复杂度,相较于线段树和树状数组不够好。
不过在大多数问题上,分块仍然是解决这些问题的一个不错选择。
一般取块的长度为 len=sqrt(n)
, 此时单次操作的时间复杂度最优,时间复杂度为:O(
n
\\sqrtn
n )
分块算法大致分为如下几步:
- 求分块后,一个块的大小。
- 对每个数都标记其对应所属的块。
- 在执行操作的时候,对于不完整的块暴力处理,完整的块进行处理的标记。
分块标记每个编号所属的块的模板:
len = sqrt(n);
for (int i = 1; i <= n; i++) id[i]=(i-1)/len+1;
区间修改,单点查询模板:
const int N = 1e5 + 10;
typedef long long int LL;
LL a[N], ad[N], id[N], n, m, len;
//ad[i] 编号为i的块加的总数 id[i] i所对应的块
void add(int l, int r, int v) //[l,r]内加v
for (int i = l; i <= min(r * 1ll, id[l]*len); i++) a[i] += v; //开头的不完整的
if (id[l] == id[r]) return;//在一个块里
for (int i = id[l] + 1; i <= id[r] - 1; i++) ad[i] += v;//中间完整的块
for (int i = (id[r] - 1) * len + 1; i <= r; i++) a[i] += v;//结束不完整的
LL query(int x) //查询x的位置的值
return a[x] + ad[id[x]];
以上是关于ACM入门之分块的主要内容,如果未能解决你的问题,请参考以下文章