區間加法,單點求值。
數列分塊是個好東西。。。我這裡詳細介紹一下分塊演算法,便於初學者的理解(我這個蒟蒻原來也是看不懂分塊)。
先把陣列分成幾個塊塊,然後就可以對它們整體操作啦。
也就是說,把乙個長度為的陣列,拆分成乙個個長度為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#includeusing 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 )
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()
return 0;
}
分塊**可以比線段樹簡潔不少,雖然暴力但十分巧妙,而且十分靈活,適用於更多的題目。
但是如果時間複雜度要求較高,分塊的o(n sqrt(n))就不能承受了,所以還是要學會乖乖打線段樹qaq。
數列分塊入門1
<-
數列分塊入門2
數列分塊入門3
數列分塊入門4
數列分塊入門5
數列分塊入門6
數列分塊入門7
數列分塊入門8
數列分塊入門9
蒲公英公主的朋友
分塊系列 數列分塊入門7 解題報告
區間乘法,區間加法,單點詢問。寫過線段樹模板2的童鞋應該很清楚了吧qaq 由於 與markdown衝突,所以用 代替o o 我們把乙個數表示為 a i tg2 b i tg1 b i tg2表示乘法標記,tg1表示加法標記。對於不完整的塊,直接 a i a i tg2 b i tg1 b i 將這個...
分塊系列 數列分塊入門6 解題報告
單點插入,單點詢問。分塊的小技巧可多啦 o o哈哈 用乙個vector來記錄每個塊的元素。vector提供了強大的insert函式,插入某個元素只要寫一點點就可以啦o o,就是乙個乙個列舉塊,直到找到插入位置屬於哪個塊,然後insert一下就ok。不過,如果插入元素集中於乙個塊的話就尷尬了qaq複雜...
LOJ 數列分塊入門 1
link 優雅的暴力,對於乙個數列,他不是乙個元素乙個元素處理,而是分成若干塊,成塊成塊的處理,以此達到降低時間複雜度的目的。首先,我們需要處理劃分的塊的大小 block 一般是根號n 塊的數目 每乙個元素對應第幾塊,然後,每一塊的左端點和右端點。完整的塊 更新 我們用lz i lz i lz i ...