--- tags: 進階資料結構 title: 分塊法 --- # 分塊法 :::info ### 題目在這裡~ - [loj 6227](https://loj.ac/p/6277) - [zerojudge b417](https://zerojudge.tw/ShowProblem?problemid=b417) - [CF 617E](https://codeforces.com/problemset/problem/617/E) - [CF 877F](https://codeforces.com/problemset/problem/877/F) ::: :::success ## 分塊思想 - 使用條件:區間相關操作 - 如果覺得線段樹太難寫,或是常數太大,亦或是空間使用太多,快來考慮這方法~ ### 正式開始 - 我們拿區間max為例子(不帶修改),考慮序列長度為 $N$ - 把陣列分成 $B$ 塊,每一塊大小為 $K = \lceil{\frac{N}{B}}\rceil$ (大約就是 $\frac{N}{B}$ ) - **對於每塊儲存該塊元素中最大值** - 這樣對於區間查詢,最多完全包含 $B-2$ 個塊,不包含在快中的元素最多 $2 \times (K-1)$ 個 - 於是乎: - 單次查詢時間:$O(B+K) = O(B+\frac{N}{B}) >= O(\sqrt{N})$ - 此時 $B ≒ \sqrt{N}$ <br> *覺得學這沒用嗎?下面我們講講**莫隊*** ::: :::success ## 普通莫隊算法 - 這邊拿區間眾數來舉例子(不帶修改) - 把陣列分成 $B$ 塊,每一塊大小為 $K = \lceil{\frac{N}{B}}\rceil$ (大約就是 $\frac{N}{B}$ ) - 我們想把所有查詢照著某個順序排序之後再處理,此技巧為**離線算法** - 同時維護目前的區間需要的資訊(當然包括答案),並且透過移動左右指針去尋找每一個詢問的答案 - 舉個簡單的例子: - 我們有詢問區間 $[5,6],[2,6],[1,2],[1,4]$ - 照著左端排序後變成 $[1,2],[1,4],[2,6],[5,6]$ - 一開始兩指針 $L=1,R=1$ - 我們開始做操作: - $R$ 往右 1 次 -> $[1,2]$ - $R$ 往右 2 次 -> $[1,4]$ - $L$ 往右 1 次,$R$ 往右 2 次 -> $[2,6]$ - $L$ 往右 3 次 -> $[5,6]$ - 當然,通常不太可能所有操作都這麼漂亮的只往右移動。如果需要往左移動,時間就得花比較久 - 我們定義排序的方法: - 兩個詢問以 $[l_i, r_i], [l_j, r_j]$ 表示 - 當 $l_i, l_j$ 在不同區塊時,$l$ 較小的排前面 - 當 $l_i, l_j$ 在同一區塊時,$r$ 較小的排前面 - 同樣的透過移動左右指針去尋找每一個詢問的答案,我們來算時間複雜度:(有 $Q$ 個詢問) - 左( $L$ )指針移動: - 塊內移動距離最多為 $K-1$ - 移到下一塊的距離最多 $2\times K-1$ - 總時間為 $O(QK)$ - 右( $R$ )指針移動: - 當 $l$ 在同一塊時總往右移動距離最多為 $N-1$ ($\times B$) - 當 $l$ 往下一塊時往左移動距離最多為 $N-1$($\times (B-1)$) - 總時間為 $O(NB)$ - 加起來: - $O(QK + NB) = O(\frac{QN}{B}+NB) >= O(N\sqrt{Q})$ - 因此 - 時間複雜度:$O(N\sqrt{Q})$ - 此時 $B = \sqrt{Q}, K = \frac{N}{\sqrt{Q}}$ ::: :::success ## 帶修改莫隊 - 這個 ::: :::success ## 實驗室 https://codeforces.com/contest/1509/problem/0 (●'◡'●)⁅⁆‹›⁽⁾¦-«»©®℗™'‘’‚‛¬÷–“”„‟⁄¤؋৻฿₡₤₧₧₥₨₢૱៛৲¥¢£֏৳৳௹₠₣₦₩₿₼₹₳₶₰₭₪₫₮₱₴₷₺﷼₽₸⇳⇷⇸⇿■▦≣≗≘≡≧≤≪≭⊃⊄︿︷﹀⺐⺓⺨⺔⺨⺔ㄊ⨊⨇⨈⨌⨉⨆⨈⨋⨎⨑⨗⨔⨭⨮⨫‱※⁜♪±⁋⁊ª‽ʬʭ□■¾⅕⅔½¼⅓⅖∝∑ :::