【学习笔记】倍增分块

倍增分块常用于处理数值递减/递增的问题,形如当 \(a_i \ge x\) 时,使 \(a_i \leftarrow a_i - x\)

分成 \([2^k,2^{k+1})\) 的若干块。

P4587

题目链接

暴力就是排个序,然后便利值域,依次加入。加入完 \(i\) 时,遍历到值域第一个不能被组成的位置 \(x\)\([1,x)\) 的数都是可以被已经加入的数组成的,所以 \(a_{i+1}\) 一定不能大于 \(x\)。一旦大于 \(x\)\(x\) 这个位置就不能被表示了。那么 \(a_{i+1} \le x\),加入 \(a_{i+1}\) 会使得下一个不能被组成的位置是 \(x+a_{i+1}\)。找到第一个不行的就行。

考虑优化这个过程,注意到 \(x\) 是单增的,所以用倍增分块。设当前在 \(x \in [2^k,2^{k+1})\),那么要往后加数,下一个数必然不能大于 \(x\)。所以可以查询 \([2^k,2^{k+1})\) 的最小值,如果最小值小于等于 \(x\),那么由于最小值 \(a_i \ge 2^k,x \ge 2^k\),所以 \(x+a_i \ge 2^{k+1}\),那么这一块的所有数必定可以取走,所以就取走 \([2^k,2^{k+1})\) 所有数加到 \(x\) 里面。每个块预处理用个 st 表就行,复杂度 \(\Theta(n (\log n+ \log V))\)

CF1515I

出现了形如 \(c \ge w_i\)\(c \leftarrow c-w_i\)。考虑按要求排序,然后模拟这个过程,发现有时候会遇到一个比 \(c\) 大的数取不了跳过,很难受。那么可以考虑特殊处理这些,设当前 \(c \in [2^k,2^{k+1})\),那么只要取到一个在 \([2^k,2^{k+1})\) 的数必然就会降级为至多 \([2^{k-1},2^k)\)。所以关注那些 \(<2^k\) 的数,如果这个都取到某个数都不能取了,那么那时候肯定是 \(c<2^k\)

那么该怎么找到这样一个数呢,考虑在线段树上维护所有 \(<2^k\) 的重量和 \(sum_k\),那么可以线段树二分找到第一个 \(sum_k >c\) 的位置,这是第二种情况。再考虑第一种,显然 \(c\) 要大于这个 \(\ge 2^k\) 的重量和之前所有 \(<2^k\) 的重量和,设这两者的和是 \(t\),那么 \(c\) 还得小于之前所有 \(\ge 2^k\) 物品的那些 \(t\) 值,可以用线段树二分求出。

所以每次 \(\log n\),做最多 \(\log V\) 次,复杂度单次是 \(\Theta(n\log n\log V)\)

posted @ 2024-07-11 22:01  FantasyNumber  阅读(3)  评论(0编辑  收藏  举报