做很久没有手搓的平衡树惹。
双 $\text{Fhq-Treap}$ 大常数写法。
题解
我们会发现,所有的操作都是基于原数列的,且没有删除操作。
考虑把三个操作分别维护。
操作二
首先考虑相邻绝对小值,如果当前位置为 $x$ ,插入 $a_x$ ,则在答案备选里添加了 $|a_x-a_{x-1}|$ 和 $|a_{x+1}-a_x|$ ,而去掉了 $|a_{x+1}-a_{x-1}|$ 。即删除了一个数,加上了两个数。而我们第二个操作需要的就是答案备选里的最小值。
本来考虑是维护最小值和次小值,结果发现这样不可做。
然后发现,我们需要求的是一个动态序列的最小值,支持插入和删除操作,结果发现就是个平衡树的板子,直接一波带走。
对于如何记录 $a_{x-1},a_{x+1}$ 并 $\mathcal O(1)$ 查询的话,记录一个数组 $Nxt[x]$ 表示加在 $x$ 之后的当前最后一个数的值,也就是原数列中第 $x+1$ 个数现在前面一个数。那么就有 $a_{x-1}=Nxt[x],a_{x+1}=Val[x+1]$ 。
操作三
然后考虑第三个操作,求一个序列的最小差值,由智慧法可以得到:如果 $x$ 有贡献,则与 $x$ 一同贡献的一定是 $x$ 的前驱后继。所以,考虑维护一棵平衡树,每插入一个数,就查找其前驱后继,并更新答案。
特判
刚开始使用的是 $\text{FHQ-Treap}$ ,交上去一发 $\textcolor{red}{\text{Wrong Answer}}$ 只有 $14pts$ ,除了板子写挂了之外,发现了这道题的一个特点,这个数列里有重复元素,而我们知道,$\text{FHQ-Treap}$ 的查找的是严格的前驱后继,但这道题所定义的前驱后继非严格,答案可能为 $1$ 。
所以需要特判。
还有平衡树的常规操作:安置哨兵。因为 $a_i,x\leq 5\times10^8$ ,所以 INF=0x3f3f3f3f
可过。
优化
在保证代码无误后,交上一发,得到 $\textcolor{darkblue}{\text{Time Limit Exceeded}}$ ,然后自嘲地开 $\text{O}_2$ ,结果还是 $\textcolor{darkblue}{\text{T}}$ 掉了一个点,我们分析一下这个做法的时间复杂度:
对于第二个操作,是 $\mathcal O(3\log n)$ ,而第三个操作是 $\mathcal O(2\log n)$,加上预处理的 $\mathcal O(2n\log n)$ ,最后得到,是一个常数巨大的 $\mathcal O(q\log n)$ ,导致了理论可过,实际 $\text{T}$ 飞的结果。
所以考虑卡常小技巧。
从刚刚的特判得知,因为没有删除操作,势能分析一波,发现操作三(操作二不行的原因是因为有删除)的答案尽可能越来越小,直到 $0$ ,那么,当最小值达到 $0$ 的时候,我们就根本不需要再维护操作三了,直接带过。
加上这个优化,吸个氧,就过了。
实现
AC Code
1 | const int MAXN=1e6+10; |