题意:
给定 n* n 矩阵A,其元素为0或1. A [ i ] [ j ] 表示第i行和第j列中的数字。最初全为0.
我们有两个操作:
- C x1 y1 x2 y2(1 <= x1 <= x2 <= n,1 <= y1 <= y2 <= n)将左上角为(x1,y1),右下角为(x2,y2)的矩阵翻转(0变成1,1变成0)。
- Q x y(1 <= x,y <= n)查询A [ x ] [ y ],输出答案。
分析:
0 1 之间的反转可以考虑 “ ^ ” (异或),但这就需要二维线段树的延时标记了,那么有更好的方法吗?
任意数字都可以通过 %2 得到 0 和 1 两个值;
那么我们把矩阵反转改为矩阵所有元素 +1 ,(0+1)%2=1,(1+1)%2=0,0相当于偶数,1相当于奇数,最后询问的时候对答案%2,不就能把 0 1 相互转换改为了矩阵加法修改吗?(还需要用到差分思想,与前缀和思想类似)
AC代码
#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=1e3+5;
int sum[N][N],n,m;
/// d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]; (差分)
/// a[i][j]=sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1]; (前缀和)
/// 由于是差分数组,既可以该减数也可以更改被减数来达到加值的目的,但为了保证所有下标大于1(lowbit!=0),则选择更改减数
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y,int v)
{
for(int i=x;i<=n;i+=lowbit(i) )
for(int j=y;j<=n;j+=lowbit(j) )
sum[i][j]+=v;
}
void ran_up(int x1,int y1,int x2,int y2)
{
update(x1,y1,1);
update(x2+1,y2+1,1);
update(x1,y2+1,-1);
update(x2+1,y1,-1);
}
int query(int x,int y)
{
int ret=0;
for(int i=x;i>0;i-=lowbit(i) )
for(int j=y;j>0;j-=lowbit(j) )
ret+=sum[i][j];
return ret&1;
}
inline void init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
sum[i][j]=0;
}
int main()
{
int T,test=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
if(test++) printf("
");
while(m--)
{
char cmd[5];
scanf("%s",cmd);
if(cmd[0]=='C')
{
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
ran_up(x1,y1,x2,y2);
}
else
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d
",query(x,y) );
}
}
}
return 0;
}
总的来说是一道区间修改,单点查询的模板题