用单调栈预处理 premin_{i} / premax_{i} 和 sufmin_{i} / sufmax_{i} 表示位置 i 之前小于 / 大于 a_{i} 最靠后的位置和位置 i 之后小于 / 大于 a_{i} 最靠前的位置。则以 a_{i} 作为区间 min / max 的区间 \left[l,r\right] 一定满足 l\in \left(premin_i / premax_i,i\right] 且 r\in \left[i,sufmin_i / sufmax_i\right)。
不难发现,区间 min / max 相同的所有区间在二维平面上构成一个矩形。使用扫描线从左向右扫,实时维护 \max\limits_{i=l}^{r}a_{i}-\min\limits_{i=l}^{r}a_{i}-r+l ,满足条件的区间该值为 0,该值一定是区间最小值,用线段树维护区间最小值及最小值数量即可。
方法二:
从左向右扫,钦定扫到的位置为区间的右端点。线段树中每个节点维护左端点在该区间的 \max\limits_{i=l}^{r}a_{i}-\min\limits_{i=l}^{r}a_{i}-r+l 最小值及最小值数量。随着右端点右移,区间 min / max 会发生变化,当且仅当单调栈发生变化。每次单调栈发生变化,线段树中都会有一段区间的 min / max 发生变化,只需要使线段树随着单调栈修改即可。
像上题一样把询问离线下来并按右端点排序。将整个序列从左向右扫,设当前扫到 r。若询问 \left[L,R\right] 未被处理过且其中 R\le r,查找 \le L 的最大的 l 满足 \left[l,r\right] 值域连续,如果有,更新答案。可以把询问放进一个堆里,每次取出 R\le r 的 L 最大的询问即可。如果查询不到区间,跳出循环即可。(因为我们将 L 排序,如果其中一个找不到答案了,则说明 1\sim L 中均不满足条件,比它小的 L 就更加无法找到答案了)