POJ 2155 Matrix(二维BIT维护差分数组)
思路:
1.这道题的要求是让我们在二维的情况下进行区间修改、单点查询;
2.我们首先转变一下思维,将取反变成+1
,如果该点是奇数,则说明该点值为1
,否则为0
;
3.我们考虑一下在一维的情况下如何进行区间取反,单点查询;这里我们需要有差分的思想,我们设差分数组为d[]
,原数组为a[]
,我们需要做的就是对于每个i
,有d[1]+d[2]+...+d[i]=a[i]
,即原数组a[i]
是d[i]
的前缀和数组;这样做有什么好处呢?我们如果想让原数组从i
到j
每个值都加上k
,我们只需要对d[i]+=k
且对d[j+1]-=k
就好了,大大降低了复杂度;而如果想查询原数组i
位置的值,我们只需要对差分数组前i
项求和就好了;用BIT
来维护这个差分数组,我们很容易可以做到这两个功能;
4.至于二维的情况,和一维情况很类似,对二维BIT
的(i,j)
位置求和,其实就是求所有(x,y)(x<=i&y<=j)
位置的和;我们此时进行(x1,y1,x2,y2)
区间修改时,需要将(x1,y1)
位置加上1
,那么接下来是不是对(x2+1,y2+1)
位置再加一次1
就好了?(注意这里加一次1
代表取反一次,我们我们之后采用模2
运算),当然不是,我们设区域A是自己要修改的区域:
我们如果直接对(x2+1,y2+1)加一,那只是对D区域取反了,那C和B被(x1,y1)加一操作所造成的影响并没有被抵消,此时我们分别对(x1,y1) (x1,y2+1)(x2+1,y1)(x2+1,y2+1)
都加一,那么A区域都被取反了,BCD区域都被取反了两次(互相抵消了),我们就成功的只对A区域进行了操作;
代码:
#include<iostream>
using namespace std;
const int maxn=1005;
int bit[maxn][maxn],n,t;
#define lowbit(x) (x&-x)
int bit_sum(int x,int y){
int s=0;
while(x>0){
int t=y;
while(t>0) s+=bit[x][t],t-=lowbit(t);
x-=lowbit(x);
}
return s;
}
void bit_add(int x,int y){
while(x<=n){
int t=y;
while(t<=n) bit[x][t]++,t+=lowbit(t);
x+=lowbit(x);
}
}
void change(int& x1,int& y1,int& x2,int& y2){
bit_add(x1,y1);
bit_add(x2+1,y2+1);
bit_add(x2+1,y1);
bit_add(x1,y2+1);
}
void End(){
for(int i=0;i<=n;i++){
for(int j=i;j<=n;j++) bit[i][j]=bit[j][i]=0;
}
puts("");
}
void solve(){
char c;
while(c=getchar(),c!='C'&&c!='Q');
if(c=='C'){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
change(x1,y1,x2,y2);
}else{
int x,y;
scanf("%d%d",&x,&y);
cout<<(bit_sum(x,y)&1)<<'\n';
}
}
int main(){
// freopen("Arutoria.txt","r",stdin);
int X; scanf("%d",&X);
while(X--){
scanf("%d%d",&n,&t);
while(t--) solve();
End();
}
return 0;
}