二维树状数组加差分
这道题需要加个差分,差分个人理解就是把正常一个数组i与i-1做差,得到的一个差分数组,然后查询时累加前缀和,这么做有很多方便的地方,比如洛谷的树状数组2。
来介绍一下差分
设数组a[]={1,6,8,5,10},那么差分数组b[]={1,5,2,-3,5}
也就是说b[i]=a[i]-a[i-1];(a[0]=0;),那么a[i]=b[1]+…+b[i];(这个很好证的)。假如区间[2,4]都加上2的话,a数组变为a[]={1,8,10,7,10},b数组变为b={1,7,2,-3,3};
b数组只有b[2]和b[5]变了,因为区间[2,4]是同时加上2的,所以在区间内b[i]-b[i-1]是不变的。
所以对区间[x,y]进行修改,只用修改b[x]与b[y+1]。
b[x]=b[x]+k;b[y+1]=b[y+1]-k
以上就是差分的应用,对于区间修改时应该想到差分,
比如这道题,就是矩阵的子矩阵修改,这种方法就非常nice
看下面这张图,修改绿色部分,只需把红色的都+1%2,再累加前缀和能满足(图片出处在水印)。
其实差分区间修改都可以理解为,比如修改(x,y)全部加2,只要把差分数组中x位置,然后再把y+1减2,就能完美解决,配上树状数组,这样修改和查询的时间复杂度就是O(logn)。
#include<cstdio>
#include<algorithm>
#include<cstring>
int t,n,k,x1,y1,x2,y2;
int e[1007][1007];
char ch[5];
void change(int x,int y,int val)
{
for(int i=x;i<=n;i+=i&(-i))
for(int j=y;j<=n;j+=j&(-j))
e[i][j]=(e[i][j]+val)%2;
}
int ask(int x,int y)
{
int ans=0;
for(int i=x;i;i-=i&(-i))
for(int j=y;j;j-=j&(-j))
ans=(ans+e[i][j])%2;
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(e,0,sizeof(e));
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)
{
scanf("%s",ch);
if(ch[0]=='C')
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
change(x1,y1,1),change(x2+1,y2+1,1),change(x1,y2+1,1),change(x2+1,y1,1);
}else if(ch[0]=='Q')
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",ask(x,y));
}
}
}
return 0;
}