之前是学会了用二维树状数组进行单点更新、区间查询、子矩阵查询,但是如果想要“子矩阵更新”、“单点查询”呢?
是不是很奇葩,其实后者都可以由前面所学的“转化”而成。
大致思路:
搞懂它我还是想了很多看了很多的0.0
首先我们换道题:如果只是在一维数组上操作的话,是不是只需要在左端点+1,右端点-1,即区间更新->单点更新了。查询单点x的时候只需要把1~x的值求和,就知道被更新的次数了,即单点查询->区间查询。(这个题就是之前的“木桩涂涂看”呀)
然后回到这个二维数组上来,我们其实也是相同的操作,只是需要考虑的情况比较多,见图:
我们想要更新绿色这块儿的子矩阵,首先,最后单点查询是要看从左上角拉到单点的一个矩阵和,那么我们就去拉。我考虑了以下几种情况,以灰框所示拉出来的矩阵:
那么,希望的效果是:如果单点(即灰框的右下角)在绿色区域里,那么灰框矩阵的和必为1,相反,如果在外面,必为0.
要达到这个效果,只需要在红色标记那四个点上分别赋值(4次单点更新),值见图。(反正根据图分析就清楚了)
还有个关键点:因为是在 0 1 0 1这样更新的,如果你进行了多次更新,比如说进行了3次,那你的值应该是1,而进行了4次,即回到初始值0. 关于这种交替更新,典型的就是用“%2”!
代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int sum[1005][1005];
int n;
int lowbit(int x)
{
return x&(-x);
}
int getsum(int x,int y)
{
int s=0;
while(x>0)
{
int t=y;
while(t>0)
{
s+=sum[x][t];
t-=lowbit(t);
}
x-=lowbit(x);
}
return s;
}
void update(int x,int y,int v)
{
while(x<=n)
{
int t=y;
while(t<=n)
{
sum[x][t]+=v;
t+=lowbit(t);
}
x+=lowbit(x);
}
}
int main()
{
int i,j,test,m,x1,y1,x2,y2,x,y;
char c;
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
{
getchar();//吸收回车
scanf("%c",&c);
if(c=='C')
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
update(x1,y1,1);
update(x2+1,y1,-1);
update(x1,y2+1,-1);
update(x2+1,y2+1,1);
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",getsum(x,y)%2);
}
}
return 0;
}