例題地址:嘟嘟嘟html
分塊其實我早都據說過,並且怎麼回事差很少都清楚了,只是一直沒有寫。如今離NOIP2018也挺近了,考慮到分塊有時候確實能水到很多的分,決定這幾天寫一寫。ios
衆所周知,分塊就是對於一個詢問區間[L, R],屬於恰好一個塊中的部分就整塊處理,多出來的散的部分就暴力處理。令塊大小爲S,則共有⌊n / S⌋塊,每一次操做多出來的部分不會超過2 * S個,那麼最壞複雜度是O(⌊n / S⌋ + 2 * S) 。爲了均衡,就取了S = √n。git
對於這道題,仍是要以一個表示數組add,但這個標記沒那麼複雜,不用下傳,只是爲了詢問單個元素的時候用。具體操做是這樣的:數組
1.修改:對於區間[L, R],令l = L / S + 1, r = R / S + 1。那麼 l + 1塊到 r - 1塊必定是整塊,直接修改sum數組。對於前面的零散部分,即[L, l * S - 1](後面有證實爲啥是這個)和後面的[(r - 1) * S, R],就直接修改a[i]。ide
2.詢問:和修改極其像。對於整塊的,ret += sum[i] (i 此時表示第幾個塊);對於單個的,ret += a[i] + add[k](k = i / S + 1)。post
上面的證實:只要求出來第k個塊所在區間便可:由於⌊i / S⌋ + 1 = k,因此⌊i / S⌋ = k - 1,則 i ∈ [(k - 1) * S, (k - 1) * S + S - 1] => i ∈ [(k - 1) * S, k * S - 1]。那麼[L, R]中前半部分就是[L, l * S - 1],後半部分就是[(r - 1) * S, R]。spa
上代碼code
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, m, S; 38 39 int bel(int x) 40 { 41 return x / S + 1; 42 } 43 ll a[maxn], sum[maxn], add[maxn]; 44 void update(int L, int R, int k) 45 { 46 int l = bel(L), r = bel(R); 47 if(l == r) //別忘不夠一個塊的狀況 48 { 49 for(int i = L; i <= R; ++i) a[i] += k, sum[bel(L)] += k; 50 return; 51 } 52 for(int i = l + 1; i < r; ++i) sum[i] += k * S, add[i] += k; 53 for(int i = L; i <= l * S - 1; ++i) a[i] += k, sum[bel(i)] += k; 54 for(int i = (r - 1) * S; i <= R; ++i) a[i] += k, sum[bel(i)] += k; 55 } 56 ll query(int L, int R) 57 { 58 ll ret = 0; 59 int l = bel(L), r = bel(R); 60 if(l == r) 61 { 62 for(int i = L; i <= R; ++i) ret += a[i] + add[l]; 63 return ret; 64 } 65 for(int i = l + 1; i < r; ++i) ret += sum[i]; 66 for(int i = L; i <= l * S - 1; ++i) ret += a[i] + add[bel(i)]; 67 for(int i = (r - 1) * S; i <= R; ++i) ret += a[i] + add[bel(i)]; 68 return ret; 69 } 70 71 int main() 72 { 73 n = read(); m = read(); S = sqrt(n); 74 for(int i = 1; i <= n; ++i) a[i] = read(), sum[bel(i)] += a[i]; 75 for(int i = 1; i <= m; ++i) 76 { 77 int d = read(), L = read(), R = read(); 78 if(d == 1) 79 { 80 ll k = read(); 81 update(L, R, k); 82 } 83 else write(query(L, R)), enter; 84 } 85 return 0; 86 }