分塊——優雅的暴力


前言:

  首先,我們來考慮這樣一個模型:有一段連續的序列a[1]~a[n],然后現在我們需要執行幾類操作:

出題人:  求出其中一段區間的和

智商180的某寶寶:哎呀,你怎么這么傻,直接記錄這個序列的前綴和不就得了?

  記錄a[1]~a[i]的和為sum[i],然后顯然有sum[i+1]=sum[i]+a[i+1],我們要求a[l]~a[r]就直接sum[r]-sum[l-1]唄。

出題人:區間加上某個值

由於某寶寶是大佬,兩分鍾后:我會一種叫線段樹的東西(一種樹形結構,可以維護區間求和和單點修改的優秀數據結構)!!!

出題人:查詢一段區間上有多少個數<k (k>0且給定)    

某寶寶:

出題人:對了,忘了告訴你了,k每次都不一樣,還有,極其的多。另外,為了防止裝*不讓寫平衡樹(另一種能干很多事情的優秀數據結構)+線段樹,占用空間不能超過****Mb

某寶寶:


下面就分享一個菜鳥也能懂得算法:分塊

分塊,顧名思義,就是把一段序列分成一小塊一小塊得來處理,維護。

我們把一段當成一個整體,只記錄維護整體的有關信息,就是分塊。

首先,對於前言說得那道題,很朴素的做法就是:

  1.從詢問區間的l到r掃過去,每回加上掃到的值,即$ans=\sum^{r}_{i=l} a[i]$ 

  2.直接把$a[i]$重新賦值不就得了 a[i]=newa[i];

  3.從詢問區間的l到r掃過去,每回遇到<k的位置,答案+1

沒錯,這種做法很傻是不是?

但是,分塊就是在這個基礎上暴力優化的!!!

假設我們總共的序列長度為n,然后我們把它切成$\sqrt{n}$塊,然后把每一塊里的東西當成一個整體來看,

現在解釋幾個本文用到的術語:

完整塊:被操作區間完全覆蓋的塊

不完整塊:操作區間不完全覆蓋的塊

然后我們先看看怎么得出答案:

  1.對於完整的塊,我們希望有個東西能直接找出這整個塊的和,於是每個塊要維護這個塊的所有元素的和。   

    .對於不完整塊,因為元素比較少(最多有  總數n /  塊數 = $\sqrt{n}$ 個) 這時候當n=1000000的時候最多有1000個,對比一下,我們可以直接暴力掃這個小塊統計答案,

    .小技巧:如果這個不完整塊被覆蓋的長度>塊維護的長度的一半,何不用這個塊的和-沒有被覆蓋的元素的值呢?

  2.這里,我們換種思路,記錄一個lazy   標記(為什么用lazy,因為我很懶),表示整個塊被加上過多少了,

    .對於完整塊,我們直接lazy+=加上的數x,塊內的和ans+=x*元素個數(因為每個元素都被加上了x)

    .對於不完整塊,直接暴力修改就好了,順便可以把lazy標記清了。

  3.哎呀,這個有點難度啊,

    .要在每個完整塊內尋找小於一個值的元素數,

     顯然我們不得不要求塊內元素是有序的,這樣就能用二分(快速在一個有序的序列里查詢的一個算法),對塊內查詢。

    .不完整的塊暴力就好

    .這樣的話需要提前對每塊里面的元素做一遍排序就好.

    .但是當有修改的話,因為整個塊同時加上(減去)一個數,每個數的相對大小是不會變的,但是如果是不完全塊就會改變,這樣的話,還是因為元素個數小,重新新排一下不就得了?

 

然后,這道題就用了一種看似高大上的方法做完了……比之前傻傻的暴力是不是好看很多呢?

在很多地方,我們可以運用到分塊的思想,化零為整,把維護每個數的值變成維護一些整體的值,

一個很常見的例子就是:為什么班主任要給班里分組?因為他可不想收作業或者回執的時候一個一個收啊qwq交給組長然后組長在交給老師多好啊qwq

這樣,我們就不用一個一個的找了qwq

然后就講完基礎了。

稍稍進階:

其實,每一塊可以維護的不止上面說的那幾種東西,我們可以維護當前區間最大公約數是多少,最大異或和是多少……

客觀的來說,分塊是可以維護很多的,只要想出來怎么預處理,對於有修改的模型怎么維護,統計答案的時候怎么累加就行。

希望對大家有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM