區間加法,單點求值。html
數列分塊是個好東西。。。我這裏詳細介紹一下分塊算法,便於初學者的理解(我這個蒟蒻原來也是看不懂分塊)。算法
先把數組分紅幾個塊塊,而後就能夠對它們總體操做啦。數組
也就是說,把一個長度爲的數組,拆分紅一個個長度爲sqrt(n)小塊(固然,最後一塊可能不完整,可是不用管),記錄每一個數所屬的塊;也就是這樣——(方便起見,咱們直接再開一個數組來記錄所屬分塊,雖然本題中能夠臨時計算,但在有些題目中這一步顯得尤其重要)spa
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] );
而後,就能夠瞎暴力辣!code
實際上,全部的分塊都是這樣。把一個數列分紅幾塊,而後對它們進行批量處理。通常來講,咱們直接把塊大小設爲sqrt(n),但實際上,有時候咱們要根據數據範圍、具體複雜度來肯定。htm
當有修改時,對於完整的塊,直接維護一個數組v記錄整個塊加過的數(每塊共同的加數),不完整的就直接暴力在原數組a上直接加。詢問時,直接輸出原數組的值+所屬塊的共同加數便可。blog
#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; }
分塊代碼能夠比線段樹簡潔很多,雖然暴力但十分巧妙,並且十分靈活,適用於更多的題目。get
可是若是時間複雜度要求較高,分塊的O(n sqrt(n))就不能承受了,因此仍是要學會乖乖打線段樹QAQ。io
數列分塊入門1 <-入門