【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;
}

一定要想好了再码!

posted @ 2016-08-05 21:09  abclzr  阅读(262)  评论(0编辑  收藏  举报