[BZOJ1176][Balkan2007]Mokia && CDQ分治+树状数组

这样的二维矩形和本身可以用树状数组在给定时间内完成 然而这时空间显然开不下了 

那么我们可以用CDQ分治将操作离散化 再将所有操作按坐标排序 这样保证了在解决较大矩阵问题的时候较小矩阵内的操作已经进行了

然后 就没有人然后了 总的来说CDQ分治是对多数次操作离线后再二分处理的一种方法? 然而我还是并不怎么会QAQ

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
#define lowbit(x) ((x) & (-(x)))
#define SF scanf
#define PF printf
using namespace std;
typedef long long LL;
const int MAXN = 2000000;
const int MAXQ = 10000;
const int MAXC = 200000;
int S, n, m, Q;
int ans[MAXQ+10];
int c[MAXN+10];
struct Node {
	int x, y, op, val, pos, id;
	bool operator < (const Node &t) const {
		if(x != t.x) return x < t.x;
		else if(y != t.y) return y < t.y;
		else return op < t.op;
	}
} A[MAXC+10], tmp[MAXC+10];
int query(int x) {
	int ret = 0;
	for(ret = 0; x; x -= lowbit(x)) ret += c[x];
	return ret;
}
void add(int x, int val) {
	for( ; x <= n; x += lowbit(x)) c[x] += val;
}
void CDQ(int L, int R) {
	if(L == R) return ;
	int mid = (L + R) >> 1, l1, l2;
	l1 = L; l2 = mid+1;
	for(int i = L; i <= R; i++) {
		if(A[i].id <= mid && !A[i].op) add(A[i].y, A[i].val);
		if(A[i].id > mid && A[i].op) ans[A[i].pos] += A[i].val * query(A[i].y);
	}
	for(int i = L; i <= R; i++) if(A[i].id <= mid && !A[i].op) add(A[i].y, -A[i].val);
	for(int i = L; i <= R; i++) 
		if(A[i].id <= mid) tmp[l1++] = A[i];
		else tmp[l2++] = A[i];
	for(int i = L; i <= R; i++) A[i] = tmp[i];
	CDQ(L, mid); CDQ(mid+1, R);
}
int main() {
	int op;
	SF("%d%d", &S, &n);
	while(true) {
		SF("%d", &op);
		if(op == 1) {
			m++;
			SF("%d%d%d", &A[m].x, &A[m].y, &A[m].val);
			A[m].id = m;
		}
		else if(op == 2) {
			int x1, x2, y1, y2, pos = ++Q;
			SF("%d%d%d%d", &x1, &y1, &x2, &y2);
			m++; A[m] = (Node) { x1-1, y1-1, 1, 1, pos, m };
			m++; A[m] = (Node) { x2, y2, 1, 1, pos, m };
			m++; A[m] = (Node) { x1-1, y2, 1, -1, pos, m };
			m++; A[m] = (Node) { x2, y1-1, 1, -1, pos, m };
		}
		else break;
	}
	sort(A+1, A+1+m);
	CDQ(1, m);
	for(int i = 1; i <= Q; i++) PF("%d\n", ans[i]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值