定义:
块状数组是基于分块思想的数据结构,较基于分治思想的数据结构如线段树、平衡树等效率较低,但通用性更强。在块状数组的基础上加以扩展,就可以得到块状链表。
原理:
普通数组在处理一些区间问题时,复杂度通常会退化至O(n)。一个朴素的想法就是将这个数组分为若干个子区间,同时维护这些子区间的统计值,如区间和、区间最值等。对于某个子区间,如果操作区间覆盖子区间,则在整体上进行修改并打标记。如果操作区间部分覆盖子区间,则将该块标记下放,对区间中被覆盖部分的元素进行暴力操作。
设数组长度为n,将其分为s块,每块c个元素,那么一次操作最坏情况是遍历所有块,复杂度为O(s)。对于不需暴力处理的块,处理的复杂度为O(1)。易知需要暴力处理的块最多只有2个,而暴力处理一个块的最坏情况是遍历块中几乎所有元素,复杂度为O(c)。总复杂度为O(s+c)。根据s*c=n,由基本不等式知,当s,c取近似n½ 时,总复杂度最小,为O(n½)。这就是分块的思想。对这个算法进行分析后会发现,我们对元素的处理方法本质上还是暴力,只是通过一些数学方法使暴力的复杂度降到了我们可以接受的范围。因此分块思想又被称为“根号的暴力”。
下面给出本人块状数组的写法,以区间和为例。
分块
定义一个结构体数组,数组元素个数为块的个数。数组里存储每一个块的左右端点,以及区间信息和标记信息。
同时保留原数组,再额外定义一个数组belong,belong[i]里存储i所属的块的下标。
#define LL long long struct block{int l,r;LL s,d;}b[maxm]; LL a[maxn],belong[maxn],sum[maxn];