【BZOJ 1176】【Balkan 2007】Mokia
http://www.lydsy.com/JudgeOnline/problem.php?id=1176
分治的例题
把每个询问拆成四个询问,整体二分里x坐标递增,按x坐标扫的时候用树状数组维护y坐标前缀和。
一开始想复杂了,按cdq分治先solve左边再处理中间再solve右边,这样每次都要对x坐标排序,常数巨大,T了好几次TwT
后来参考了别人的代码,发现自己一开始就想复杂了。这道题不需要在solve完后还是保持原来的按x坐标递增的顺序,也不需要先处理出左边的信息才能更新右边的信息。
这样直接分治啊~~~~~处理完一大块左边对右边的贡献再递归处理左右两块。只要一开始对x坐标排序即可,solve的过程从整到散,不需要再进行排序。
一开始还忘了离散化,每次清空树状数组都用memsetヽ(*´Д`*)ノ后来发现从前往后扫一遍把原先加的减回去会快得多。
时间复杂度$O(mlogmlogw)$,m的含义为所有修改和询问的数量,w的含义为离散化y坐标后的y坐标最大值,即树状数组的上界。
#include<cstdio> #include<cstring> #include<algorithm> #define lowbit(x) (x&(-x)) using namespace std; int in() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = (k << 3) + (k << 1) + c - '0'; return k * fh; } struct node { int op, x, y, a, id, pos; bool operator < (const node &A) const { return x == A.x ? (y == A.y ? pos < A.pos : y < A.y) : x < A.x; } } Q[200003], q[200003]; int s, w, m = 0, ans[40003]; namespace CDQ { int bits[180003]; void update(int x, int num) { for(; x <= w; x += lowbit(x)) bits[x] += num; } int Qsum(int x) { int ret = 0; for(; x; x -= lowbit(x)) ret += bits[x]; return ret; } void solve(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; for(int i = l; i <= r; ++i) { if (Q[i].op == 1 && Q[i].id <= mid) update(Q[i].y, Q[i].a); if (Q[i].op == 2 && Q[i].id > mid) ans[Q[i].pos] += Q[i].a * Qsum(Q[i].y); } for(int i = l; i <= r; ++i) if (Q[i].op == 1 && Q[i].id <= mid) update(Q[i].y, -Q[i].a); int tl = l, tr = mid + 1; for(int i = l; i <= r; ++i) if (Q[i].id <= mid) q[tl++] = Q[i]; else q[tr++] = Q[i]; for(int i = l; i <= r; ++i) Q[i] = q[i]; solve(l, mid); solve(mid + 1, r); } } int H[180003], cnt = 0, anscnt = 0; int main() { s = in(); w = in(); int x1, y1, x2, y2; for(int x = in(); x != 3; x = in()) if (x == 1) { Q[++m].op = 1; Q[m].x = in(); Q[m].y = in(); Q[m].a = in(); Q[m].id = m; Q[m].pos = 0; H[++cnt] = Q[m].y; } else { x1 = in(); y1 = in(); x2 = in(); y2 = in(); H[++cnt] = y1 - 1; H[++cnt] = y2; ans[++anscnt] = s * (x2 - x1 + 1) * (y2 - y1 + 1); ++m; Q[m] = (node) {2, x1 - 1, y1 - 1, 1, m, anscnt}; ++m; Q[m] = (node) {2, x1 - 1, y2, -1, m, anscnt}; ++m; Q[m] = (node) {2, x2, y1 - 1, -1, m, anscnt}; ++m; Q[m] = (node) {2, x2, y2, 1, m, anscnt}; } sort(H + 1, H + cnt + 1); cnt = unique(H + 1, H + cnt + 1) - H; w = cnt - 1; for(int i = 1; i <= m; ++i) Q[i].y = lower_bound(H + 1, H + cnt, Q[i].y) - H; sort(Q + 1, Q + m + 1); CDQ::solve(1, m); for(int i = 1; i <= anscnt; ++i) printf("%d\n", ans[i]); return 0; }
一定要想好了再码!
NOI 2017 Bless All