bzoj 1176 cdq分治套树状数组
题面:
维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
Input
第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小
接下来每行为一下三种输入之一(不包含引号):
"1 x y a"
"2 x1 y1 x2 y2"
"3"
输入1:你需要把(x,y)(第x行第y列)的格子权值增加a
输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出
输入3:表示输入结束
Output
对于每个输入2,输出一行,即输入2的答案
思路:正常思路用树状数组套树状数组,但是w范围过大,开不下。考虑用cdq分治套树状数组。我们用cdq分治对x坐标排序,用树状数组维护y坐标,把询问用差分思想拆分成四个不同的询问即可。
代码:
#include <bits/stdc++.h> #define LL long long #define lowbit (x & (-x)) using namespace std; const int maxn = 200010; int tot, tot_ans, n; struct query{ int type, x, y, pos, flag; }; query q[maxn], tmp[maxn]; int c[maxn * 10], ans[maxn]; void add(int x, int y) { for (; x <= n; x += lowbit) c[x] += y; } int ask(int x) { int ans = 0; for (; x; x-= lowbit) { ans += c[x]; } return ans; } void clear(int x) { for (; x <= n; x += lowbit) { c[x] = 0; } } void cdq(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq(l, mid); cdq(mid + 1, r); int l1 = l, l2 = mid + 1, pos = l; while(l1 <= mid && l2 <= r) { if(q[l1].x <= q[l2].x) { if(q[l1].type == 1) { add(q[l1].y, q[l1].pos); } tmp[pos++] = q[l1++]; } else { if(q[l2].type == 2) { ans[q[l2].pos] += q[l2].flag * ask(q[l2].y); } tmp[pos++] = q[l2++]; } } while(l1 <= mid) tmp[pos++] = q[l1++]; while(l2 <= r) { if(q[l2].type == 2) { ans[q[l2].pos] += q[l2].flag * ask(q[l2].y); } tmp[pos++] = q[l2++]; } for (int i = l; i <= mid; i++) { if(q[i].type == 1) { clear(q[i].y); } } for (int i = l; i <= r; i++) q[i] = tmp[i]; } int main() { int l1, r1, l2, r2, x, op, val; scanf("%d%d", &x, &n); while(~scanf("%d", &op) && op != 3) { if(op == 1) { scanf("%d%d%d", &l1, &r1, &val); q[++tot] = (query){1, l1, r1, val, 0}; } else { scanf("%d%d%d%d", &l1, &r1, &l2, &r2); tot_ans++; ans[tot_ans] = x * (l2 - l1 + 1) * (r2 - r1 + 1); q[++tot] = (query){2, l1 - 1, r1 - 1, tot_ans, 1}; q[++tot] = (query){2, l1 - 1, r2, tot_ans, -1}; q[++tot] = (query){2, l2, r1 - 1, tot_ans, -1}; q[++tot] = (query){2, l2, r2, tot_ans, 1}; } } cdq(1, tot); for (int i = 1; i <= tot_ans; i++) { printf("%d\n", ans[i]); } }