思路
分块是一种数据结构,往往把数据分为许多块来处理。让每一个 整块 维护一些信息。暴力区间两个端点的小块。时间复杂度一般带根号。
例题:loj 数列分块入门 1-9
数列分块入门 1
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间加法,单点查值。
数据范围:$1<=n<=50000 , -2^{31}<=others,ans<=2^{31}-1$
Solution
把 $n$ 个数分成 $sqrt(n)$ 个块。$tag_i$ 表示第 $i$ 个块整个加上多少。
当遇到一个块 $i$ 被 $[l,r]$ 完全包含,使 $tag_i+=c$。如果块 $j$ 与 $[l,r]$ 有交集,暴力修改 $j$ 内被 $[l,r]$ 包含的元素。时间复杂度为 $O(n$ * $sqrt(n))$
设点 $i$ 所属的块为 $be_i$,未更改之前的值为 $a_i$,它最终的值即为 $tag_{be_i}+a_i$
Code
1 |
|
数列分块入门 2
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间加法,询问区间内小于某个值 $x$ 的元素个数。
数据范围:$1<=n<=50000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
对每个块内的元素进行排序,记录它原来的位置。区间加法如 $1$ 中操作。对于被完全包含的块,在块内二分,找到第一个大于等于 $x$ 的元素,该元素 $-1$ 到块的起点都是 $<x$ 的元素。可以使用 $lower$_$bound$
一个简单转换:$a_i+tag_{be_i}<x$ -> $a_i<x-tag_{be_i}$
对于不完整的块,直接暴力即可。总时间复杂度为 $O(n$*$sqrt(n)log_n)$
Code
1 |
|
数列分块入门 3
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间加法,询问区间内小于某个值 $x$ 的前驱(比其小的最大元素)
数据范围:$1<=n<=100000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
对 $2$ 稍作改动。在二分的时候取 $max$ 作为答案。
Code
1 |
|
数列分块入门 4
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间加法,区间求和。
数据范围:$1<=n<=50000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
$sum_i$ 表示第 $i$ 个块的和,$tag_i$表示第 $i$ 个块整体加上多少。在整块上打 $tag$,暴力两边时更改 $sum$ 和原值。查询时,每个点的值为 $a_i+tag_{be_i}$,每个块的值为 $sum_i+tag_i$*$(end-st+1)$
Code
1 |
|
数列分块入门 5
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间开方,区间求和。
数据范围:$1<=n<=50000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
一个数经过几次开方之后就会变成 $0$ 或 $1$,此后再开方不会改变其值。可以标记一个块内所有数值是不是已经改变不了了。如果无法改变,直接跳过。否则暴力。
Code
1 |
|
数列分块入门 6
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及单点插入,单点询问,数据随机生成。
数据范围:$1<=n<=100000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
做法1
使用链表维护,把当前数插入到 $l$ 前面,并使当前数加入 $l$ 所在块。对于每一次查询 $r$,先找出 $r$ 在哪一个块里,然后暴力这个块。
优化
如果数据不是随机的,每个块的大小会远远大于 $sqrt(n)$。每 $sqrt(n)$ 次插入之后重新分块。(代码没有优化)
Code
1 |
|
数列分块入门 7
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间乘法,区间加法,单点询问。
数据范围:$1<=n<=100000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
设 $mul_i$ 为块 $i$ 整体乘上几,$add_i$ 为块 $i$ 整体加上几。块 $i$ 内的数乘以 $c$,$mul_i$ * $=c$,$add_i$ * $=c$。块 $i$ 内的数加上 $c$,$add_i+=c$。
特别注意:暴力两边的时候需要把乘法标记和加法标记都去掉,加到原始数组里面去。
Code
1 |
|
数列分块入门 8
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及区间询问等于一个数 $c$ 的元素,并将这个区间的所有元素改为 $c$。
数据范围:$1<=n<=100000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
设$tag_i$ 表示块 $i$ 的值。$hav_i$ 表示块 $i$ 内的元素是否相同。
对于整块修改,$tag_i=c/hav_i=true$。对于两边,先把整块的 $tag$ 都去掉,再使 $hav_i=0$
Code
1 |
|
数列分块入门 9
Description
给出一个长为 $n$ 的数列,以及 $n$ 个操作,操作涉及询问区间的最小众数。
数据范围:$1<=n<=100000 , -2^{31}<=others, ans<=2^{31}-1$
Solution
此题与链接中题目不同之处在于,此题没有修改操作,并且需要离散化。
由于太菜,窝的代码 $T$ 了几个点,只能拿到 $92 pts$。
Code 92pts
1 |
|
还是借(chao)鉴(xi)一下大佬 $hzwer$ 的 $std$ 吧…