ABC444E Sparse Range
e---sparse-range">E - Sparse Range
1. 题意梗概
给定一个长度为 的数组 和一个正整数 。
求有多少子区间 满足:区间内任意两个元素之差的绝对值都 。
2. 逻辑推导
其实看到这个 子区间,计数,范围约束。很容易会想到滑动窗口(双指针)的写法。
起手就可以固定右端点 ,尝试寻找最小的合法左端点 。
如果区间 合法,那么它的所有子区间 也都合法。
当加入新元素 时,我们需要检查它是否与当前窗口 内的元素冲突。
即 内的元素是否存在一个值在区间 。
前面都很简单,都很好想,但问题就在这里,这个判断怎么写呢?
首先排除暴力,因为一旦暴力复杂度就是 ,原地爆炸,双指针优化了个寂寞
(bushi。
我们需要一种能够快速进行范围查询的数据结构。
2.1 辅助数据结构
- 权值树状数组
不难想到可以用权值树状数组来维护这个查询,但我们回到数据范围 ,,。
这个值域可不好维护啊,注意到 ,好像可以离散化处理,这样就是可以接受范围的权值树状数组了。
Anyway,这里就会出现新的问题,因为每次加入的右端点之后,新的限制值域 这两个边界的值没有离散化,所以这样离散化很麻烦,很难处理(理论上应该是可行的,不推荐)。
- 平衡树
利用红黑树的特性,我们可以在 的时间内完成这个动态维护和查找。
只需要 lower_bound( A[r] - D + 1 ) 找到窗口内第一个 的数。
然后再判断这个数是否冲突,即是否 ,如果冲突就删掉,收缩窗口。
2.2 set or multiset
直观上,如果数组中存在重复元素,应该使用 multiset。但结合题意分析:如果数组中存在两个相同的数,则它们的差值为 ,而题目给定的 ,这显然是矛盾的。
这就意味着,合法区间内是不允许出现重复元素的,因此这里使用 set 也是能 AC 的,但逻辑上可能会有点奇怪。
不过这里我采用 multiset 维护窗口中的元素(赛场上没想到上面这个点)。
3. 代码实现
▶
AcCode
1 | |
ABC444E Sparse Range
http://miqiu.space/posts/54bff8b4/