[BZOJ1176][Balkan2007]Mokia
Posted Elder_Giang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1176][Balkan2007]Mokia相关的知识,希望对你有一定的参考价值。
1176: [Balkan2007]Mokia
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 2633 Solved: 1184
[Submit][Status][Discuss]
Description
维护一个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的答案
Sample Input
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
5
HINT
保证答案不会超过int范围
CDQ分治
还是把每种查询拆成四个
然后时间直接不用排了。。
在分治过程中按照$x$归并,然后一边归并一边把$y$加到权值树状数组里面
树状数组清空可以打时间戳
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint() { int f = 1, n = 0; char ch = *++ptr; while (ch < ‘0‘ || ch > ‘9‘) { if (ch == ‘-‘) f = -1; ch = *++ptr; } while (ch <= ‘9‘ && ch >= ‘0‘) { n = (n << 1) + (n << 3) + ch - ‘0‘; ch = *++ptr; } return f * n; } int s, w; int C[2000000 + 10], T[2000000 + 10] = { 0 }, flag = 0; inline int Query(int pos) { int ret = 0; for (int i = pos; i; i -= i & -i) if (T[i] == flag) ret += C[i]; return ret; } inline void Update(int pos, int val) { for(int i = pos; i <= w; i += i & -i) if (T[i] != flag) { T[i] = flag; C[i] = val; } else C[i] += val; } struct Que { int type, x, y, val; Que() {} Que(int _type, int _x, int _y, int _val) : type(_type), x(_x), y(_y), val(_val) {} }q[200000 + 10], tp[200000 + 10]; int ans[10000 + 10] = {0}; void CDQ(int l, int r) { if (l == r) return; int mid = l + r >> 1, ll = l, rr = mid + 1, tcnt = 0; CDQ(l, mid); CDQ(mid + 1, r); flag++; while (ll <= mid && rr <= r) { if (q[ll].x <= q[rr].x) { if (q[ll].type == 1) Update(q[ll].y, q[ll].val); tp[++tcnt] = q[ll++]; } else { if (q[rr].type == 2) ans[q[rr].val] += Query(q[rr].y); else if(q[rr].type == 3) ans[q[rr].val] -= Query(q[rr].y); tp[++tcnt] = q[rr++]; } } while (ll <= mid) tp[++tcnt] = q[ll++]; while (rr <= r) { if (q[rr].type == 2) ans[q[rr].val] += Query(q[rr].y); else if(q[rr].type == 3) ans[q[rr].val] -= Query(q[rr].y); tp[++tcnt] = q[rr++]; } for (int i = 1; i <= tcnt; i++) q[l + i - 1] = tp[i]; } int sz = 0; int main() { fread(buf, sizeof(char), sizeof(buf), stdin); s = readint(); w = readint(); int opt, x1, y1, x2, y2, a, qtime = 0; while ((opt = readint()) != 3) { x1 = readint(); y1 = readint(); if (opt == 1) { a = readint(); q[++sz] = Que(1, x1, y1, a); } else { qtime++; x2 = readint(); y2 = readint(); q[++sz] = Que(2, x2, y2, qtime); q[++sz] = Que(2, x1 - 1, y1 - 1, qtime); q[++sz] = Que(3, x1 - 1, y2, qtime); q[++sz] = Que(3, x2, y1 - 1, qtime); // ans[qtime] = (x2 - x1 + 1) * (y2 - y1 + 1) * s; } } CDQ(1, sz); for (int i = 1; i <= qtime; i++) printf("%d\n", ans[i]); return 0; }
以上是关于[BZOJ1176][Balkan2007]Mokia的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ1176][Balkan2007]Mokia cdq+树状数组
bzoj千题计划144:bzoj1176: [Balkan2007]Mokia
BZOJ1176:[Balkan2007]Mokia——题解