COCI 2015/2016 Day 8 PROKLETNIK
PROKLETNIK
题目描述:给出\(n\)个数,定义一段连续的数为魔法串是该区间的左右端点值正好是区间的最小值与最大值(最小值可以在左也可以在右,最大值也一样)。\(Q\)个询问,每次询问一个区间\([L, R]\),问该区间的子区间为魔法串的最大长度。
solution
离线所有的询问,现在考虑左小右大的魔法串。然后如果可以维护\(i\)之前的点为左端点的最长魔法串的答案,那么以\(i\)为右端点的询问的答案就是\([L, R]\)取最大值。
问题是如何维护。
因为现在只考虑左小右大的魔法串,所以考虑维护一个单调递增的队列,先考虑\(i\)入队
1、\(i\)不小于队尾。设\(taller[i]\)表示前\(i\)个数比\(i\)大的,且离\(i\)最近的位置,那么队列中在\(taller[i]\)右边的点都可以以\(i\)为右端点,而且\(i\)是当前它们的最优解。(下一个点会解释为什么只有队列中的点才能被更新答案)可以考虑用线段树来维护这个队列中的点的最优解,线段树对应队列的第几个数(即对应队列下标),\(i\)进队。
2、\(i\)小于队尾。这时,队尾不可能再成为魔法串的左端点(因为\(i\)小于队尾,队尾不是最小值),也就是说队尾的答案不会也不能在更新,所以可以把队尾的答案取出,存进另一棵线段树(以队列中的值为下标,即原来数的下标)或树状数组。不断地把队尾取出,直到\(i\)不小于队尾。这时\(i\)不能更新队列中的任何一个数(因为\(i\)不是最大值),所以\(i\)直接进队。
对于以\(i\)为右端点的询问,求出第二棵线段树\([L, R]\)的最大值,以及\(L\)在队列中的位置\(w\),然后求队列的那棵线段树\(w\)之后的最大值,取这两个值的最大值就是答案。
时间复杂度:\(O((Q+n)logn)\)