题意
给出一个n*n的01矩阵,一开始全是0,给出q个操作,一种是给出一个矩阵的左上角坐标和右下角坐标(题意定义左上为原点),将这个矩阵内的所有元素0变成1,1变成0,另一种操作是询问一个点是0还是1
其中n<=10^3 q<=5*10^4
多组测试数据,保证小于十组。
分析
用二维树状数组,修改时,设左上角(x1,y1),右上角(x2,y2),就在(x1,y1),(x2+1,y1),(x1,y2+1),(x2+1,y2+1)各加1,查询时直接求前缀和%2,即这个点和原点形成的矩形里元素的和。画图可以发现,对于每次修改,在矩形内的点求和时会加一,但是如果在矩形外的区域,就一定会加二的倍数(这是这道题比较巧妙的点),最后被%掉。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1006
using namespace std;
int bit[MAXN][MAXN],x1,y1,x2,y2,n,T,q;
char op;
inline int lowbit(int x)
{
return x&(-x);
}
void change(int x,int y)
{
for(;x<=n;x+=lowbit(x))
for(int i=y;i<=n;i+=lowbit(i))
bit[x][i]++;
}
int addup(int x,int y)
{
int re=0;
for(;x;x-=lowbit(x))
for(int i=y;i;i-=lowbit(i))
re+=bit[x][i];
return re;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(bit,0,sizeof(bit));
scanf("%d%d",&n,&q);
for(int i=1;i<=q;i++)
{
scanf("\n%c",&op);
if(op=='C')
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
change(x1,y1);
change(x2+1,y1);
change(x2+1,y2+1);
change(x1,y2+1);
}
else
{
scanf("%d%d",&x1,&y1);
printf("%d\n",addup(x1,y1)%2);
}
}
if(T) printf("\n");
}
}