[bzoj1176]mokia (cdq+树状数组)

题意:二维区间单点修改,查询给定矩形的和。

数据范围应该挺大,几十万,离散化之后也没法用二维数据结构做。

话说这是大视野上的vip题。吾等屌丝只有拿来水一下自己OJ上的二维树状数组的模板题了。。反而还慢一点。

这是我的第二道cdq分治的题,不是很熟练,还是照着别人代码敲的。

感觉这题要比cash好做多了。。cash一题中要划分后归并(即快排+归排),因为那道题里面每个节点考虑左儿子对右儿子的影响时需要左儿子的值全部搞定了。所以要用一个归并将两个曲线合并上传给父亲使用。

而这道题其实更适合入门。它的影响是可以直接得出的,并且不同层之间互不干扰。所以只需要划分即可,但是要注意完成影响之后为了下一层的使用需要将所有的影响清空,即将树状数组复原。这个复原的时间开销挺大的。。(说不定可以可持久化?)

注:这份代码可能在大视野上过不到。。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define DB double
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define x1 x12a345
#define y1 y54s321
#define x2 x19d4f5
#define y2 ya54fa2
const int MAXN = 200030;
int S, N;

struct dot
{
	int id, x, y, v, qq;
	dot () {}
	dot (int a, int b, int c, int d, int e)
	{ id=a, x=b, y=c, v=d, qq=e; }
	bool operator < (const dot&b) const
	{
		if (x != b.x) return x < b.x;
		if (y != b.y) return y < b.y;
		return qq < b.qq;
	}
} po[200000], np[200000];

namespace BIT
{
	int bt[MAXN];
	void add(int i, int x)
	{
		for (; i<=N; i+=i&-i)
			bt[i] += x;
	}
	int qsum(int i)
	{
		int r = 0;
		for (; i>0; i-=i&-i)
			r += bt[i];
		return r;
	}
};

int ans[200000], qn, pn;

void cdq(int L, int R)
{
	using namespace BIT;
	if (L == R) return;
	int mid = (L + R) >> 1;
	rep(i, L, R)
	{
		if (po[i].id<=mid && !po[i].qq)
			add(po[i].y, po[i].v);
		if (po[i].id>mid && po[i].qq)
			ans[po[i].qq] += po[i].v * qsum(po[i].y);
	}
	rep(i, L, R)
		if (po[i].id<=mid && !po[i].qq)
			add(po[i].y, -po[i].v);
	int l1 = L, l2 = mid+1;
	rep (i, L, R)
	{
		if (po[i].id <= mid) np[l1 ++] = po[i];
		else np[l2 ++] = po[i];
	}
    rep (i, L, R) po[i] = np[i];
	cdq(L, mid), cdq(mid+1, R);
}

int main()
{
	scanf("%d%d", &S, &N);
	int typ, x1, y1, x2, y2;
	while (scanf("%d",&typ), typ!=3)
	{
		switch(typ)
		{
			case 1:
				scanf("%d%d%d", &x1, &y1, &x2);
				++x1, ++y1;
				++pn, po[pn] = dot(pn, x1, y1, x2, 0);
				break;
			default:
				scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
				++x1, ++y1, ++x2, ++y2, ++qn;
				++pn, po[pn] = dot(pn, x1-1, y1-1, 1, qn);
				++pn, po[pn] = dot(pn, x2, y1-1, -1, qn);
				++pn, po[pn] = dot(pn, x1-1, y2, -1, qn);
				++pn, po[pn] = dot(pn, x2, y2, 1, qn);
		}
	}
	sort(po+1, po+pn+1);
	cdq(1, pn);
	rep(i, 1, qn) printf("%d\n", ans[i]);
	return 0;
}


你可能感兴趣的:([bzoj1176]mokia (cdq+树状数组))