分块算法
分块算法相当于一种优雅的暴力,一般块的大小是取sqrt(n);
第一题:区间加法与区间查值。
修改区间时,两头的区间要格外来加,中间的直接加区间标记值即可。两头的小区间枚举也只有sqrt(n)的复杂度,中间的大区间枚举也只有sqrt(n)的复杂度。
查询区间时,直接等于那点的值加上所在区间的标记值。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> using namespace std; using LL = long long; LL getint(); int N, M; LL block, val[500005], blg[500005], tag[1005]; void add(int l, int r, int key); int main(){ N = getint(), block = sqrt(N); int i; for(i = 1; i <= N; i++) val[i] = getint(); for(i = 1; i <= N; i++) blg[i] = (i - 1) / block + 1; for(i = 1; i <= N; i++){ int op, x, y, key; op = getint(), x = getint(); y = getint(), key = getint(); if(op == 0){ add(x, y, key); }else printf("%lld\n", val[y] + tag[blg[y]]); } return 0; } void add(int l, int r, int key){ int i, top; for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) val[i] += key; if(blg[l] != blg[r]) for(i = (blg[r] - 1) * block + 1; i <= r; i++) val[i] += key; for(i = blg[l] + 1; i <= blg[r] - 1; i++) tag[i] += key; } LL getint(){ LL res = 0, mark = 1; char ch = getchar(); while(ch<'0' || ch>'9'){ if(ch == '-') mark = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') res = 10 * res + ch - '0', ch = getchar(); return mark * res; }
分块第二题
区间加法与询问某个区间内大于某个数的个数。
先对每个块排好序,然后对于每个块二分查找即可。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <vector> using namespace std; using LL = long long; int N; LL block, val[50005], blg[50005], tag[1005]; vector<LL> val_blg[1005]; void add(int, int, int); int query(int, int, int); int main(){ ios::sync_with_stdio(false); cin >> N, block = sqrt(N); int i; for(i = 1; i <= N; i++) cin >> val[i]; for(i = 1; i <= N; i++) blg[i] = (i - 1) / block + 1, val_blg[blg[i]].push_back(val[i]); for(i = 1; i <= blg[N]; i++) sort(val_blg[i].begin(), val_blg[i].end()); for(i = 1; i <= N; i++){ int op, x, y, key; cin >> op >> x >> y >> key; if(op == 0) add(x, y, key); else cout << query(x, y, key * key) << endl; } return 0; } void reset(int block_id); void add(int l, int r, int key){ int i, top; for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) val[i] += key; reset(blg[l]); if(blg[l] != blg[r]){ for(i = (blg[r] - 1) * block + 1; i <= r; i++) val[i] += key; reset(blg[r]); } for(i = blg[l] + 1; i <= blg[r] - 1; i++) tag[i] += key; } int query(int l, int r, int key){ int i, top, res = 0; for(i = l, top = min(blg[l] * block, 1LL * r); i <= top; i++) if(val[i] + tag[blg[i]] < key) res++; if(blg[l] != blg[r]) for(i = (blg[r] - 1) * block + 1; i <= r; i++) if(val[i] + tag[blg[i]] < key) res++; for(i = blg[l] + 1; i <= blg[r] - 1; i++) res += lower_bound(val_blg[i].begin(), val_blg[i].end(), key - tag[i]) - val_blg[i].begin(); return res; } void reset(int x){ int i, top; val_blg[x].clear(); for(i = (x - 1) * block + 1, top = min(x * block, 1LL * N); i <= top; i++) val_blg[x].push_back(val[i]); sort(val_blg[x].begin(), val_blg[x].end()); }