一、题面
二、分析
楼教主出的题,是二维树状数组非常好的题,还结合了开关问题(开关变化的次数如果为偶数,状态不变,奇数状态相反)。
题意就是给了一个二维的坐标平面,每个点初始值都是0,然后给一个矩形的区域,对该区域的点的状态进行反转。然后在中间插有查询,查该点的状态。
其实,还是对反转次数的一个研究,这里为了能快速的查找一个点的反转次数,加上又是二维,且有区间修改,所以选择二维树状数组进行处理,整个二维数组记录的就是反转的次数。
每反转一次,就对整个矩形区间进行修改,反转次数加1,最终查询的时候就是查一共反转了多少次,记得取余2,如果是偶数,就不变,是奇数,就变1。
注意处理二维树状数组区间更新的时候,假设给的矩形对角线的点为(x1,y1),(x2,y2)。那么更新的时候是
$add(x1,y1,v) + add(x1,y2+1, -v) + add(x2+1, y1, -v) + add(x2+1,y2+1,v)$
为什么这样,看下图,因为你如果只更新(x1,y1),那么就会更新多的区域,就要想办法减去,但是减了之后,发现又减重了一部分,所以需要又加回来。
三、AC代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 5 using namespace std; 6 7 const int MAXN = 1e3 + 15; 8 9 int BIT[MAXN][MAXN]; 10 11 void add(int x, int y, int v) 12 { 13 for(; x < MAXN; x += x & -x) 14 { 15 for(int j = y; j < MAXN; j += j & -j) 16 { 17 BIT[x][j] += v; 18 } 19 } 20 } 21 22 int sum(int x, int y) 23 { 24 int ans = 0; 25 for(; x; x -= x & -x) 26 { 27 for(int j = y; j; j -= j & -j) 28 { 29 ans += BIT[x][j]; 30 } 31 } 32 return ans%2; 33 } 34 35 void update(int x1, int y1, int x2, int y2, int v) 36 { 37 add(x1, y1, v); 38 add(x2 + 1, y2 + 1, v); 39 add(x1, y2 + 1, -v); 40 add(x2 + 1, y1, -v); 41 } 42 43 int main() 44 { 45 //freopen("input.txt", "r", stdin); 46 int T; 47 scanf("%d", &T); 48 while(T) 49 { 50 int N, Q, x1, y1, x2, y2; 51 char c; 52 memset(BIT, 0, sizeof(BIT)); 53 scanf("%d %d", &N, &Q); 54 for(int i = 0; i < Q; i++) 55 { 56 getchar(); 57 scanf("%c %d %d", &c, &x1, &y1); 58 59 if(c == 'C') 60 { 61 scanf("%d %d", &x2, &y2); 62 update(x1, y1, x2, y2, 1); 63 } 64 else 65 { 66 printf("%d ", sum(x1, y1)); 67 } 68 } 69 if(--T) 70 printf(" "); 71 } 72 return 0; 73 }