UOJ191,你失败的原因只有一个:你没有强制在线。
首先这个序列末位加加减减很烦,于是换成操作树,这样就变成查询链的信息了。
注意到一个向量 \((x_1,y_1)\) 比 \((x_2,y_2)\) 优秀的条件是 \(x_1*B+y_1*A>x_2*B-y_2*A\),也就是 \((x_1-x_2)*B>(y_1-y_2)*A\),\(\frac {x_1-x_2}{y_1-y_2}>\frac A B\)。
于是树剖。
容易发现询问是又链上若干个前缀与一个区间组成的。于是我们似乎只需要实现一个可持久化分块,然后在上面二分即可。
但是最后那个区间怎么办?别急,我们后面再进行讨论。
如果直接使用平衡树复杂度应该是十分优秀的 \(O(m\log^2n)\),加上平衡树的大常数能过就有鬼了。
考虑进行神秘优化。
将对前缀的询问拆下来,然后提前对每条链建立好凸包,凸包应该包含的信息有坐标和在树上的深度。然后离线对斜率排序。
每次询问之前将凸包的指针向后跳(相当于预处理处理二分的位置),因为每个数最多被跳一次所以是 \(O(n)\) 的。
每次询问凸包时需要询问凸包上的“前驱”(前面第一个没被标记的)和“后继”(类似前者),将查询的位置与查询的值再次离线下来。
现在的问题变为查询序列上前面第一个比自身小的值与后面第一个比自身小的值。
将序列的元素从大到小排序,每扫到一个元素就将自己与前面的元素合并,然后前面第一个比自身小的值相当于前面第一个块的最后一个元素,后继同理。
使用并查集即可做到 \(O(m\log n\alpha(n))\)。排序使用基数排序即可保证复杂度。虽然说也有严格的线性序列并查集就是了
但是你一共有 \(O(m\log n)\) 个询问啊?
对询问分块,分成 \(\log n\) 块,每一块只有 \(O(m)\) 个询问,这样子离线就可以接受了。
但是别忘了还有一些区间。但是数量已经降低到 \(O(m)\) 个了。
对前面的故技重施,但是变成了查询前面第一个在 \([l,r]\) 中的元素。因为只有 \(O(m)\) 个询问所以可以随便用主席树。
但是计算空间的时候你会发现空间刚好是 65MB。。。
考虑二分这个值的位置。问题变为查询矩阵中数的个数。
这个差分一下用树状数组即可。但是这样还需要离线,所以不妨直接把二分搬到最外面去,变成整体二分。
这样子做的常数极小,虽然是 \(O(m\log^2n)\) 却比 \(O(m\log n)\) 快不少。毕竟主席树的大常数应该都听说过了
最终复杂度 \(O(n\log n+m\log n\alpha(n)+m\log^2n)\) 或 \(O(n\log n+m\log^2n)\),空间复杂度 \(O(n+m)\),也许大概可以通过此题。