ABC282_H
上次做这题挺有感触,本来想写点东西,奈何写了一半 Typora 卡死,写的东西都丢失了,这次又有了新的感悟,决定一起写出来。
这道题看到前面的 \(\max\) 就可以想到,可以对于每个 \(a_i\) 求出其支配区间,然后 \(a_i\) 会将支配区间分为两段,枚举短的那一段,对长的那一段进行二分即可。
这样看似复杂度会高达 \(\mathcal{O}(n^2\log n)\),实际上却是 \(\mathcal{O}(n\log^2n)\) 的优秀算法,足以通过本题。
以下我们将说明复杂度为 \(\mathcal{O}(n\log^2n)\) 的原因:
观察可以得出,支配区间实际上呈二叉树的结构,具体地说,最大值的支配区间是整个数列,然后数列被最大值分为两段,左段的最大值支配了整个左段,右段的最大值支配整个右段,那么从整段的最大值点向左右两段的最大值点连边,于是可以递归处理左右两段,建出一棵二叉树(这棵二叉树实际上是一棵笛卡尔树)。
可以观察到一个性质,某个节点对应的子树大小,和它的支配区间长度相等。
那么对于每个结点,枚举其左右儿子的支配区间中 长度较短的那一段,这个复杂度就相当于是 dsu on tree 的复杂度,是 \(\mathcal{O}(n\log n)\) 的。
那么在本题中算法的复杂度便是 \(\mathcal{O}(n\log^2 n)\)。
在本题中,实现上不必建出笛卡尔树,直接单调栈求出支配区间后枚举 \(a_i\) 二分即可。
做完本题还可以去看看 CF1777F。