[JOIST 2022] Fish 2
Tag: 线段树,双指针
相当无敌的题目。
称所有满足 \(\sum\limits_{i=l}^{r} a_{i}< \min(a_{l-1},a_{r+1})\) 的区间 \([l,r]\) 为限制区间。
容易注意到以下性质:
\(\mathrm{Observation \ 1:}\) 限制区间要么包含,要么不交。
这个结论用反证法很好证明。
\(\mathrm{Observation \ 2:}\) 一个端点固定时,限制区间个数是 \(O(\log V)\) 的。
考虑把一个限制区间 \([l,r]\) 向外拓展,容易发现每次拓展都会使区间和至少 \(\times 2\) ,由此不难证明。
考虑一个限制区间 \([l,r]\) ,容易发现其含义为区间内所有的鱼都无法突破这个限制。我们对每条鱼维护最小的限制区间使得区间包含这条鱼。直接暴力求每条鱼的限制区间,然后对每个询问 \([L,R]\) check 一下鱼的限制区间是否在询问区间外部,计算答案即可。这样做是 \(O(nq)\) 的。
这样似乎不大行,我们要找一种快速计算区间答案的手段。方便起见,如果一条鱼能吃完区间 \([l,r]\) 内的所有鱼,我们就称 \([l,r]\) 为子限制区间。显然限制区间的子区间并非都是子限制区间,因为吃鱼是可以有顺序的。
注意到询问带修,我们尝试用线段树维护区间答案。为了实现维护,我们需要找一种高效的手段实现 pushup 。我们考虑对线段树每个节点对应区间 \([L,R]\) 维护一些在 pushup 中有用的子限制区间,能同时顶到 \(L\) 和 \(R\) 的区间个数就是该节点答案。
显然这个东西不能简单线性相加维护,因为左右区间结合的一部分有可能会让一些新区间贡献答案。具体地,对于两个子节点 \([L,M]\) ,\([M+1,R]\) ,如果左侧有子限制区间 \([l,M]\) 并且在考虑右区间以后可以向两侧拓展成 \([L,R]\) ,这种区间就可以作为新区间贡献答案。为此,我们需要记录所有有可能成为答案的区间。
注意到如下性质:
\(\mathrm{Observation \ 3:}\) 节点 \([L,R]\) 的候选区间 \([l,r]\) 必定满足 \(l = L\) 或 \(r = R\)。
很好证,因两边都够不到的区间已经被锁死了,节点向上 pushup 的时候端点只会增大,它还是会被锁死在里面,永远不会成为答案。
于是我们开两个 vector ,对节点 \(p\) 保存所有只顶到右端点的区间 \([L,r_{i}]\) 和只顶到左端点的区间 \([l_{i},R]\) ,两边都顶到的区间直接记一个 \(cnt\) 表示此类区间的个数即可。
考虑在 pushup 的过程中合并这些区间。设两个子节点为 \([L,M]\) 和 \([M+1,R]\) ,我们先处理左节点的候选区间,右节点的过程就是左节点的镜像。考虑按区间长度将所有顶到右端点的候选区间排序。设父节点为 \(fa\) ,两个子节点为 。我们先找到一个最小的区间 \([l_{i},M]\) 满足区间能够拓展到 \(R\) ,考虑倒序遍历剩余的大区间 ,将这个区间向左拓展,边拓展边把经过的区间更新合并到父节点 \(r\) 处。 同理求出最小的区间 \([l_{i},M]\) 满足其可以拓展到 \(L\) 且右端点不会拓展到 \(r\) ,把往外的所有区间合并到 \(l\) 处。
由于小区间可达的大区间一定可达,考虑双指针维护这个过程。我们尝试从左侧最小的区间出发,贪心地向右匹配右节点处顶到左侧的区间\([M+1,r_{i}]\) 即可高效完成合并。
由于性质 \(2\) 的存在,左右区间个数都是 \(O(\log V)\) 的,这保证了上述操作时间复杂度的正确性。
实现时没必要记录区间的左右端点,往 vector 里传一个等价类 \(\{sum,cnt,out\}\) 表示此类区间元素和,此类区间个数和以及挡住区间拓展的端点 ,维护等价类的合并即可。
总时间复杂度 \(O((n+q\log n)\log V)\) 。

浙公网安备 33010602011771号