POJ 2155 二维线段树(压位水过)

题目就不贴了。0 - 1 矩阵,修改 + 询问。

看 ccl 写了一个二维线段树,好像时间被暴虐了 (1100 ms 吧)。。。于是无聊写了一下。。。

看到 0 - 1 矩阵,马上想到压位。。。然后对于每一位建树状数组。。。相当于分块树状数组了。。。

然后用树状数组做差分前缀和。。。每次都是 O(lgn) 的。。。

相当于我的回答是 O(lgn) 的,而修改是 O(n * lgn * 1000 / 64) 的。

结果竟然是 125 ms,rank 7(第三快的时间),而且空间小得出奇。。。压位真是神器啊。。。

错点:用 int 存 unsigned long long 做返回值了。。。结果各种 WA。。。不过好在养成了每次先拍的习惯。。。

Code :

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define maxn 1000
#define maxs 62
#define ull unsigned long long

void getint(int & A)
{
	char c = getchar();
	for (; '0' > c || c > '9'; c = getchar());
	A = c - '0', c = getchar();
	for (; '0' <= c && c <= '9'; c = getchar()) A = A * 10 + c - '0';
}

int n, m, x1, y1, x2, y2;
ull block[maxs + 5];
ull a[maxn / maxs + 2][maxn + 1];

ull query(int A, int B)
{
	ull * p = a[A], res = 0;
	for (; B; B -= B & - B) res ^= p[B];
	return res;
}

void modify(int A, int B1, int B2, const ull & C)
{
	ull * p = a[A]; ++ B2;
	for (; B1 <= n; B1 += B1 & - B1) p[B1] ^= C;
	for (; B2 <= n; B2 += B2 & - B2) p[B2] ^= C;
}

void revise()
{
	int i, j; ull k;
	int L = (x1 - 1) / maxs + 1;
	int R = (x2 - 1) / maxs + 1;
	if (L == R)
	{
		k = block[x2 - x1 + 1] << ((x1 - 1) % maxs);
		modify(L, y1, y2, k);
	}
	else
	{
		for (i = L + 1; i < R; ++ i) modify(i, y1, y2, block[maxs]);
		j = L * maxs - x1 + 1, k = block[j] << (maxs - j);
		modify(L, y1, y2, k);
		j = R * maxs - x2, k = block[maxs - j];
		modify(R, y1, y2, k);
	}
}

void getans()
{
	int A = (x1 - 1) / maxs + 1;
	ull B = query(A, y1);
	puts((B >> ((x1 - 1) % maxs)) & 1 ? "1" : "0");
}

void prepare()
{
	int i; block[0] = 1;
	for (i = 1; i <= maxs; ++ i) block[i] = block[i - 1] << 1;
	for (i = 0; i <= maxs; ++ i) -- block[i];
}

int main()
{
	freopen("2155.in", "r", stdin);
	freopen("2155.out", "w", stdout);
	
	int X; prepare();
	for (getint(X); X --; )
	{
		getint(n), memset(a, 0, sizeof a);
		for (getint(m); m --; )
			if (getchar() == 'Q')
			{
				getint(x1), getint(y1);
				getans();
			}
			else
			{
				getint(x1), getint(y1), getint(x2), getint(y2);
				revise();
			}
		if (X) puts("");
	}
	
	return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值