之前一直咕着的,因為一些特殊的原因把這道題更掉算了……
有一個對值域莫隊+線段樹的做法,復雜度\(O(n\sqrt{n} \log n)\)然而牛客機子實在太慢了沒有希望(Luogu上精細實現似乎可以過)。
考慮對序列進行塊大小為\(B=\sqrt{n}\)的分塊。對於某一個塊來說,如果我們要對這個整塊進行詢問,那么一次詢問一定會保留這\(B\)個數按照值域排序之后的一段區間,其余都變成\(0\)。也就是說本質不同的詢問只有\(O(B^2)\)種。
如果可以對這\(O(B^2)\)種詢問處理出每一種對應詢問下這一塊中的最大子段和、最大前綴和、最大后綴和和總和,那么對於一組詢問就只需要把整塊的信息拿過來把散塊暴力合並就可以了。
注意到計算最大子段和具有結合律,我們考慮分治。當我們在解決一段區間\((l,r)\)時候,先從中間劈成\((l,mid)\)和\((mid+1,r)\)兩半遞歸下去做,遞歸邊界是\(l=r\)。接下來我們考慮當我們解決了\((l,mid)\)和\((mid+1,r)\)的問題時如何合並。
首先我們可以使用歸並得到當前區間按照值域排序后的數組,然后我們需要通過左右兩邊得到的答案來得到左右端點分別取在其中某個位置的時候的答案。假設需要求值域左右端點為\((l,r)\)的答案,那么在左區間中找到最小的\(\geq l\)的值\(l_1\)和最大的\(\leq r\)的值\(r_1\),那么對於左區間來說詢問\((l,r)\)等價於詢問\((l_1,r_1)\),而后者在之前處理的答案里面存在。所以我們找到\(l_1,r_1\)就可以得到左區間的信息,右區間同理。我們可以通過這個方式來得到當前區間下的所有答案。
使用單調性將每一層合並的復雜度降低為區間長度的平方,那么分治的復雜度可以由\(T(n) = 2T(\frac{n}{2}) + O(n^2)\)計算,根據主定理\(T(n) = O(n^2)\)。也就是我們將所有塊的答案預處理出來的復雜度是\(O(n \sqrt{n})\)的。
然后我們只需要對於每一次詢問找到每一塊內這組詢問的值域區間對應在塊上的哪一個區間。在線做需要二分,所以可以把詢問離線下來,把所有需要求位置的所有值域位置先排序然后雙指針求出對應位置。復雜度\(O(n \sqrt{n})\)。
題外話:這東西常數賊大,盡量避免使用STL是卡常的很好的選擇……
