【cdq分治】【P4390】[BOI2007]Mokia 摩基亚

Description

给你一个 \(W~\times~W\) 的矩阵,每个点有权值,每次进行单点修改或者求某子矩阵内权值和,允许离线

Input

第一行是两个数字 \(0\) 和矩阵大小 \(W\)

下面每行可能会出现如下参数

\(1,x,y,A\) 单点修改格子 \(x,y\)\(A\)

\(2,x_1,y_1,x_2,y_2\) 查询给定矩阵的权值和

\(3\) 结束查询与修改

Output

对每个查询给出一行作为答案

Hint

\(1~\leq~W~\leq~2000000\)

修改不超过 \(1.6e5\)

查询不超过 \(1e4\)

保证答案在整形范围内

Solution

这不傻逼题,直接树状数组套treap完事了

我们考虑离线乱搞一下

将查询改为每次查询二维前缀和容斥的形式进行四次单点查询。

我们考虑对 \(x,y\) 的前缀和查询:

我们只需要考虑修改时间在该次查询之前,且 \(x_0~\leq~x~\land~y_0~\leq~y\) 的修改操作 \((x_0,y_0)\)

我们发现这是一个标准的cdq分治模型:

第一维为时间序,第二维为 \(x\) 坐标,第三维为 \(y\) 坐标。

时间序默认有序,每次考虑前半部分的 \(x_0~\leq~x\) 的点中 \(y_0~\leq~y\) 的点对答案的贡献,用树状数组来统计这部分答案

时间复杂度 \(O(n~\log^2 n)\),空间复杂度 \(O(n~\log n)\)

Code

#include <cstdio>
#include <vector>
#include <iostream>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif

typedef long long int ll;

namespace IPT {
	const int L = 1000000;
	char buf[L], *front=buf, *end=buf;
	char GetChar() {
		if (front == end) {
			end = buf + fread(front = buf, 1, L, stdin);
			if (front == end) return -1;
		}
		return *(front++);
	}
}

template <typename T>
inline void qr(T &x) {
	char ch = IPT::GetChar(), lst = ' ';
	while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
	while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
	if (lst == '-') x = -x;
}

namespace OPT {
	char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
	if (x < 0) {x = -x, putchar('-');}
	int top=0;
	do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
	while (top) putchar(OPT::buf[top--]);
	if (pt) putchar(aft);
}

const int maxn = 2000010;

struct OP {
	int x, y, id, v;

	inline void print() {
		std::cerr << x << ' ' << y << ' ' << id << ' ' << v << std::endl;
	}
};
std::vector<OP> Q;

int n, cnt;
int ans[maxn], tree[maxn];

int query(int);
int lowbit(int);
void cdq(int, int);
void update(int, int);

int main() {
	freopen("1.in", "r", stdin);
	int a, b, c, d;
	qr(a); qr(n); a = 0; qr(a); 
	while (a != 3) {
		if (a == 1) {
			a = b = c = 0; qr(a); qr(b); qr(c);
			Q.push_back({a, b, 0, c});
		} else {
			a = b = c = d = 0; qr(a); qr(b); qr(c); qr(d);
			Q.push_back({c, d, ++cnt, 1});
			Q.push_back({a - 1, b - 1, cnt, 1});
			Q.push_back({c, b - 1, cnt, -1});
			Q.push_back({a - 1, d, cnt, -1});
		}
		a = 0; qr(a);
	}
	cdq(0, Q.size() - 1);
	for (int i = 1; i <= cnt; ++i) qw(ans[i], '\n', true);
	return 0;
}

void cdq(int l, int r) {
	if (l == r) return;
	int mid = (l + r) >> 1;
	cdq(l, mid); cdq(mid + 1, r);
	std::vector<OP>temp;
	int pre = l;
	for (int i = mid + 1; i <= r; ++i) {
		while ((pre <= mid) && (Q[pre].x <= Q[i].x)) {
			if (Q[pre].id == 0) update(Q[pre].y, Q[pre].v);
			temp.push_back(Q[pre++]);
		}
		ans[Q[i].id] += Q[i].v * query(Q[i].y);
		temp.push_back(Q[i]);
	}
	for (int i = l; i < pre; ++i) if (Q[i].id == 0) update(Q[i].y, -Q[i].v);
	while (pre <= mid) temp.push_back(Q[pre++]);
	for (int i = l; i <= r; ++i) Q[i] = temp[i - l];
}

inline int lowbit(int x) {return x & -x;}

void update(int x, int v) {
	while (x <= n) {
		tree[x] += v; x += lowbit(x);
	}
}

int query(int x) {
	int _ret = 0;
	while (x) {
		_ret += tree[x];
		x -= lowbit(x);
	}
	return _ret;
}
posted @ 2019-02-23 16:34  一扶苏一  阅读(204)  评论(0编辑  收藏  举报