poj 2155 (含解释)二维树状数组

传送门:https://vjudge.net/problem/POJ-2155

题意:给你一个n*n的01矩阵,初始时为0,然后每次有两种操作,第一种是一个子矩阵的翻转,另一种是询问某点的值。

这题是从白书上来的,增加了我对二维数组的理解。

我们先想一下一维的情况,要实现一个区间增加某一个值,只需要用差分数组,每次实现操作只需要a[l]+1,以及a[r+1]-1,便可。

但是二维用差分数组就有点难受了。但是起码思想是有的,就是一个区域加某值,可以修改它的端点。

那我这里二维的,a[x][y]里面的值表示以(x,y)为左上角,(n,n)为右下角的矩阵翻转的次数,所以根据容斥原理可以解决第一个操作

(这一篇博文解释的很好了:https://blog.csdn.net/acm_fish/article/details/69842523

然后询问(x,y)的值,其实也就是问(x,y)的翻转次数,根据上面a[x][y]的含义可以知道,求以(x,y),(0,0)的矩阵的值的和便可。

这里用二维树状数组,其实也就是多了一个for而已

 1 // Cease to struggle and you cease to live
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <queue>
 8 #include <vector>
 9 #include <set>
10 #include <map>
11 #include <stack>
12 using namespace std;
13 typedef long long ll;
14 const int N=1000+8;
15 int n;
16 int tr[N][N];
17 char s[3];
18 void add(int x,int y){
19     for(int tx=x;tx<=n;tx+=tx&-tx){
20         for(int ty=y;ty<=n;ty+=ty&-ty){
21             ++tr[tx][ty];
22         }
23     }
24 }
25 int sum(int x,int y){
26     int res=0;
27     for(int tx=x;tx;tx-=tx&-tx){
28         for(int ty=y;ty;ty-=ty&-ty){
29             res+=tr[tx][ty];
30         }
31     }
32     return res;
33 }
34 int main() {
35     int T;scanf("%d",&T);
36     for(int t=1;t<=T;++t){
37         memset(tr,0,sizeof(tr));
38         scanf("%d",&n);
39         int qn;scanf("%d",&qn);
40         for(int i=1;i<=qn;++i){
41             scanf("%s",s);
42             int x1,x2,y1,y2;
43             scanf("%d%d",&x1,&y1);
44             if(s[0]=='C'){
45                 scanf("%d%d",&x2,&y2);
46                 add(x1,y1);add(x2+1,y2+1);add(x1,y2+1);add(x2+1,y1);
47             }
48             else{
49                 printf("%d\n",sum(x1,y1)%2);
50             }
51         }
52         cout<<endl;
53     }
54     return 0;
55 }
View Code

 

posted @ 2019-05-18 22:18  小布鞋  阅读(162)  评论(0编辑  收藏  举报