[POJ - 2155] Matrix (二维树状数组)

链接

http://poj.org/problem?id=2155

题意

给你一个 n × n n\times n n×n的矩阵,现在让你对它进行 k k k次操作,共两种,第一种是告诉你 ( x 1 ,   y 1 ) , ( x 2 ,   y 2 ) (x1,\ y1),(x2,\ y2) (x1, y1),(x2, y2),对于
x 1 ≤ x ≤ x 2 x1\leq x\leq x2 x1xx2 y 1 ≤ y ≤ y 2 y1\leq y\leq y2 y1yy2 ( x ,   y ) (x,\ y) (x, y),进行反转,即原来是1的变为0,是0的变为1,第二种是查询一个 ( x ,   y ) (x,\ y) (x, y)的值;

分析

  使用树状数组;对于一维的树状数组,考虑一维上的对于 [ l , r ] [l,r] [l,r]区间同时加上x,我们使用树状数组的操作是在 l l l加上 x x x,在 r + 1 r+1 r+1加上一个 − x -x x,求位置 y y y的值直接求 s u m ( y ) sum(y) sum(y)即可;另外,使用这种方法的前提是差分的思想,一般情况下我们的数组初始化都是为0,所以差分之后还是0,所以我们默认的是我们的操作都是基于差分的操作(这句话的意思是,如果你有一个非零的序列,你要使用树状数组给它某个区间进行加上某个值的操作,你必须求出它的差分数组,然后对差分数组操作);
  
  那么考虑二维树状数组,对于一个矩形区域的反转,我们将它视为给改矩形区域都加上一个1的操作,当我们需要求某个点 ( x ,   y ) (x,\ y) (x, y)值的时候,我们就直接二维 s u m ( x ,   y ) sum(x,\ y) sum(x, y),类似一维时候的正常操作,对于这个求出来的值假设是 P P P,那么这个 P P P的意义就是我们对 ( x ,   y ) (x,\ y) (x, y)这个点进行反转操作的次数,对于反转操作来说,它只有两种可能要么是0要么是1,而初始的时候是0,反转奇数次一定是1,偶数次一定是0,所以我们只需要把我们求得的 ( x ,   y ) (x,\ y) (x, y)位置的反转次数 P P P除以2就可以了;
  这里就省略了具体怎么对矩形区域的加1操作,还需要注意0的 l o w b i t lowbit lowbit无意义,所以代码中有了++的操作;

代码
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

#define INF 0x7f7f7f7f
#define MAXN 1000005
#define N 200005
#define P 2
#define MOD 99991

typedef long long ll;

namespace fastIO {
	//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
	//char buf[(1 << 22)], *p1 = buf, *p2 = buf;
	inline int read() {
		char c = getchar(); int x = 0, f = 1;
		while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
		while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
		return x * f;
	}
}

using namespace fastIO;
using namespace std;

int q, n, t, c[1006][1011];

void insert(int x, int y) {
	for (int i = x; i <= n + 3; i += i & -i)
		for (int j = y; j <= n + 3; j += j & -j)
			c[i][j]++;
}

int sum(int x, int y) {
	if (x <= 0 || y <= 0)return 0;
	int res = 0;
	for (int i = x; i > 0; i -= i & -i)
		for (int j = y; j > 0; j -= j & -j)
			res += c[i][j];
	return res&1;
}

int main() {
	q = read();
	while (q--) {
		n = read(), t = read();
		char o[2]; int x1, y1, x2,y2;
		memset(c, 0, sizeof(c));
		for (int i = 1; i <= t; i++) {
			scanf("%s", o);
			if (o[0] == 'C') {
				x1 = read(), y1 = read(), x2 = read(), y2 = read();
				x1++, x2++, y1++, y2++;
				insert(x1, y1);
				insert(x1, y2 + 1);
				insert(x2 + 1, y1);
				insert(x2 + 1, y2 + 1);
			}
			else {
				x1 = read(), y1 = read();
				x1++, y1++;
				printf("%d\n", sum(x1, y1));
			}
		}
		printf("\n");
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值