數列分塊入門1 解題報告
阿新 • • 發佈:2018-12-01
寫在前面
數列分塊是個好東西。。。我這裡詳細介紹一下分塊演算法,便於初學者的理解(我這個蒟蒻原來也是看不懂分塊)。
分塊簡要介紹
先把陣列分成幾個塊塊,然後就可以對它們整體操作啦。
也就是說,把一個長度為的陣列,拆分成一個個長度為sqrt(n)小塊(當然,最後一塊可能不完整,但是不用管),記錄每個數所屬的塊;也就是這樣——(方便起見,我們直接再開一個數組來記錄所屬分塊,雖然本題中可以臨時計算,但在有些題目中這一步顯得尤為重要)
scanf( "%d", &n ); m = (int)sqrt(n); for ( int i = 1; i <= n; ++i ) p[i] = ( i - 1 ) / m + 1; for ( int i = 1; i <= n; ++i ) scanf( "%d", &a[i] );
然後,就可以瞎暴力辣!
實際上,所有的分塊都是這樣。把一個數列分成幾塊,然後對它們進行批量處理。一般來說,我們直接把塊大小設為sqrt(n),但實際上,有時候我們要根據資料範圍、具體複雜度來確定。
正題
當有修改時,對於完整的塊,直接維護一個數組v記錄整個塊加過的數(每塊共同的加數),不完整的就直接暴力在原陣列a上直接加。詢問時,直接把原陣列的值+所屬塊的共同加數即可。
程式碼
#include<cstdio> #include<cmath> using namespace std; #define MAXN 50005 int n, a[MAXN], p[MAXN], m, v[300]; int opt, l, r, c; void Add( int l, int r, int c ){ if ( p[l] == p[r] ){//同屬一分塊時直接暴力即可 for ( int i = l; i <= r; ++i ) a[i] += c; return; } for ( int i = l; p[i] == p[l]; ++i ) a[i] += c;//對於兩邊不完整(即使完整也不管,看做不完整)的分塊,直接暴力即可 for ( int i = r; p[i] == p[r]; --i ) a[i] += c; for ( int i = p[l] + 1; i <= p[r] - 1; ++i ) v[i] += c;//記錄完整分塊的共同加數 } int main(){ scanf( "%d", &n ); m = (int)sqrt(n); for ( int i = 1; i <= n; ++i ) p[i] = ( i - 1 ) / m + 1;//記錄所屬分塊 for ( int i = 1; i <= n; ++i ) scanf( "%d", &a[i] ); for ( int i = 1; i <= n; ++i ){ scanf( "%d%d%d%d", &opt, &l, &r, &c ); if ( opt == 0 ) Add( l, r, c ); else printf( "%d\n", v[p[r]] + a[r] );//所屬分塊共同加數+原陣列的值 } return 0; }
總結
分塊程式碼可以比線段樹簡潔不少,雖然暴力但十分巧妙,而且十分靈活,適用於更多的題目。
但是如果時間複雜度要求較高,分塊的O(n sqrt(n))就不能承受了,所以還是要學會乖乖打線段樹QAQ。
數列分塊系列目錄
數列分塊入門1 <-
數列分塊入門2 還沒呢QAQ
數列分塊入門3 還沒呢QAQ
數列分塊入門4 還沒呢QAQ
數列分塊入門5 還沒呢QAQ
數列分塊入門6 還沒呢QAQ
數列分塊入門7 還沒呢QAQ
數列分塊入門8 還沒呢QAQ
數列分塊入門9 還沒呢QAQ
蒲公英 還沒呢QAQ
公主的朋友 還沒呢QAQ