理解了很久。。
首先分析一维的情况:首先对于每个数A定义集合up(A)表示{A, A+lowestbit(A), A+lowestbit(A)+lowestbit(A+lowestbit(A))...} 定义集合down(A)表示{A, A-lowestbit(A), A-lowestbit(A)-lowestbit(A-lowestbit(A)) ... , 0}。可以发现对于任何A<B,up(A)和down(B)的交集有且仅有一个数。这样,在改变区间[a,b]时,我们只用更改down(b)和down(a-1)的值,用数状数组实现。在求点i的状态的时候就直接求up(i).因为之前所说的性质,在修改和i有关的区间的时候,向上求和只会记录一次,不会重复记录,这样就把改变的次数求出来了。由于是0,1变换,所以不用记录实际改变了多少次,所以只要改变就加一,结果模2就可以了。
后来敲二维数状数组的时候二了,WA了两次。。
a27400 | 2155 | Accepted | 4368K | 547MS | G++ | 928B | 2011-10-03 14:22:34 |
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
int c[1010][1010];
int n;
int lowbit(int x)
{
return x&(-x);
}
int sum(int x,int y)
{
int s=0;
int i,j;
for(i=x;i<=n;i+=lowbit(i))
for(j=y;j<=n;j+=lowbit(j))
s+=c[i][j];
return s;
}
void update(int x,int y)
{
int i,j;//先开始没用i,j真是太傻了><
for(i=x;i>0;i-=lowbit(i))
for(j=y;j>0;j-=lowbit(j))
c[i][j]+=1;
}
int main(void)
{
int T;
scanf("%d",&T);
while(T--)
{
memset(c,0,sizeof(c));
int p;
scanf("%d %d",&n,&p);
char s[3];
int x,y,xx,yy;
int i;
for(i=1;i<=p;i++)
{
scanf("%s",s);
if(s[0]=='C')
{
scanf("%d %d %d %d",&x,&y,&xx,&yy);
update(xx,yy);
update(xx,y-1);
update(x-1,yy);
update(x-1,y-1);//被重复修改的再修改回来
}
else if(s[0]=='Q')
{
scanf("%d %d",&x,&y);
printf("%d\n",sum(x,y)%2);
}
}
puts("");//注意每组数据后面的空行
}
return 0;
}