2018年四校联合周赛-第二场 B.异或和问题(二维树状数组)

异或和问题

TimeLimit:1000MS  MemoryLimit:256MB
64-bit integer IO format:%I64d
Problem Description

现在有一个n行n列的矩阵。初始状态下,矩阵里的所有值都为0。行的编码是从1到n,列的编码也同样是从1到n. 

ai, j.是在第i行第j列的数。子矩阵(x0, y0, x1, y1)是由ai, j. (x0 ≤ i ≤ x1, y0 ≤ j ≤ y1)组成的矩阵。
现在需要进行下列的两个操作:
       1.查询(x0, y0, x1, y1):输出子矩阵(x0, y0, x1, y1)的异或和。
       2.更新(x0, y0, x1, y1, v):将子矩阵(x0, y0, x1, y1)中的每一个数都异或上一个v

Input

第一行包含两个数:n(1<=n<=1000),m(1<=m<=100000)  m是需要操作的次数。

对于接下来的m行:
如果该行的第一个数是1,表示查询操作,后面是x0, y0, x1, y1.
如果该行的第一个数是2,表示更新操作,后面是x0, y0, x1, y1, v.
数据保证:1 ≤ x0 ≤ x1 ≤ n, 1 ≤ y0 ≤ y1 ≤ n  ,0 ≤ v < 262   

Output

对于每一个查询操作,输出对应的结果,占单独的一行。

SampleInput
2 3 
2 1 1 2 2 1
2 1 1 1 1 2
1 1 1 2 2
SampleOutput
2


 Note:
  经过第一个操作得到  
          1  1 
          1  1
  经过第二个操作得到
          3  1
          1  1
  询问:3XOR1XOR1XOR1=2  


分析:首先,本题进行的是区间更新,以及区间查询的操作。

根据异或具有的性质,奇数个a相异或等于a , 偶数个a相异或等于0,

如果将 (x0, y0, x1, y1)区间异或一个v,那么对后面求区间异或和的影响,无非是两种,等于更新前的异或和,
或者在原本的异或和基础上异或一个v.所以可以考虑将影响直接作用于单点上,进而转变为单点更新。

如果是在一个一维的区间里进行操作的话,比如现在有数组b1,b2,b3,b4,b5....bn
对于区间[2,n]异或上一个v的话,再查询区间[1,m].

如果m为奇数,也就是与更新时的左端点奇偶性不同,
在异或过程,就会不断的互相抵消,最后为一开始的b1^b2^b3..^bm.
如果m为偶数,也就是与更新时的左端点奇偶性相同,就将上述结果再异或上v;

所以处理的时候,就可以当作单点更新,可以把左端点b2分为两种状态,
在m为奇数查询下的状态和在m为偶数查询下的状态,分别为b2和b2^v;

同理,如果在区间[a,b]上进行更新操作,相当于进行两个操作,将[a,n]异或一次,再将[b+1,n]异或一次
如果在区间[a,b]上进行查询操作,相当于[1,b]^[1,a-1]

二维的情况下,也是相同的道理,只是要区分两个坐标的奇偶性,所以用到4个状态来储存。
现在求解就变成了 单点更新和区间查询,就可以直接使用二维树状数组了.
这个将区间更新转为单点更新的操作,类似于差分树状数组对加减法的区间操作。

代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=1010;
LL c[2][2][MAXN][MAXN];
int n,m;
LL val;
int lowbit(int x)
{
 return x&-x;
}
void add(int a,int b) { for(int i=a;i<=n;i+=lowbit(i)) for(int j=b;j<=n;j+=lowbit(j)) c[a&1][b&1][i][j]^=val; } LL sum(int a,int b) { int aa=a&1,bb=b&1; LL ans=0; for(int i=a;i>=1;i-=lowbit(i)) for(int j=b;j>=1;j-=lowbit(j)) { ans^=c[a&1][b&1][i][j]; } return ans; }
int main() { scanf("%d%d",&n,&m); int x1,x2,y1,y2,op; LL ans;
for(int i=1;i<=m;i++) { scanf("%d",&op);
if(op==1) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); ans=sum(x2,y2)^sum(x2,y1-1)^sum(x1-1,y2)^sum(x1-1,y1-1); printf("%I64d\n",ans); }
else { scanf("%d%d%d%d%I64d",&x1,&y1,&x2,&y2,&val); add(x1,y1),add(x2+1,y1),add(x1,y2+1),add(x2+1,y2+1); }
}
return 0; }

 



posted @ 2018-03-18 23:17  hinata_hajime  阅读(264)  评论(0编辑  收藏  举报