分塊算法
首先來談談什么是分塊呢?直接理解就是把一個整體分成若干個部分,這就是所謂的字面理解分塊。
就如剛才所說,這就是分塊的思想,而分塊算法又稱優雅的暴力。
好啦,現在我們正式來理解分塊算法......
一般來說,分塊嗎?你總要知道自己每塊要分的大小對吧。這個已經解決了,一般每塊都是分為sqrt(n)的大小,而一共有n / sqrt(n)塊,當然,如果不能整除的話,你需要分的數量還是要加一的。之后你每塊都要有一個標記吧,比如說:你有1,2,3,4,5這5個數,每塊的大小是2, 一共3塊, 其中 1 和 2 屬於一塊,3 和 4 屬於一塊,依次類推。一般存在一個belong[] 數組里面,方便后續操作。嘻嘻...你以為這樣就完了嗎?那你就錯了,還需要一樣東西,就是你需要記錄每一塊的范圍,放心,這個很簡單的,就是定義兩個數組,分別記錄在當前塊所在范圍的左端點和右端點。這個很容易實現的,就是上一個區間的右端點加一,和當前區間的右端點就是所求的范圍。是不是有點暈,好吧。我們看一下代碼吧,這樣便於理解。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int a[maxn]; //a數組存取原始數據 int belong[maxn]; //belong數組表示每個數屬於哪一塊方便調用 int L[1010]; //L和R表示各塊左右端點 int R[1010]; int block,num; //block各塊大小,num塊數量 //修改,視情況而定 void change(int l, int r, int add) { //略..(可見下面模板題) } //查詢,同上 int query(int l, int r) { //略.. } //建立各塊(各個分塊這個操作大致一樣) void build(int n) { block = sqrt(n);//每塊的大小 num = n / block; //一共有多少塊 if (n % block) { num++; //如果不整除顯然數量加個1 } for(int i = 1; i <= num; i++) { L[i] = (i - 1) * block + 1; //上一個區間的右端點加一就是當前區間的左端點 R[i] = i * block; //直接計算當前區間的右端點 } R[num] = n; //最后一個右端點一定是結尾 for(int i = 1; i <= n; i++) { belong[i] = (i - 1) / block + 1; //belong數組 } //初始狀態維護......(省略) }
int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } build(n); //詢問......(省略) }
