「分塊系列」數列分塊入門1 解題報告

數列分塊入門1

題意歸納

區間加法,單點求值。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 <-入門

數列分塊入門2

數列分塊入門3

數列分塊入門4

數列分塊入門5

數列分塊入門6

數列分塊入門7

數列分塊入門8

數列分塊入門9

蒲公英

公主的朋友

相關文章
相關標籤/搜索