例题地址:嘟嘟嘟
分块其实我早都听说过,而且怎么回事差不多都清楚了,只是一直没有写。现在离NOIP2018也挺近了,考虑到分块有时候确实能水到不少的分,决定这几天写一写。
众所周知,分块就是对于一个询问区间[L, R],属于刚好一个块中的部分就整块处理,多出来的散的部分就暴力处理。令块大小为S,则共有?n / S?块,每一次操作多出来的部分不会超过2 * S个,那么最坏复杂度是O(?n / S? + 2 * S) 。为了均衡,就取了S = √n。
对于这道题,还是要以一个表示数组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]。
2.询问:和修改极其像。对于整块的,ret += sum[i] (i 此时表示第几个块);对于单个的,ret += a[i] + add[k](k = i / S + 1)。
上面的证明:只要求出来第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]。
上代码
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 }
原文:https://www.cnblogs.com/mrclr/p/9863833.html