CF341D-Iahub and Xors

题目

一个\(n\times n\)的零矩阵\(a\)\(m\)次操作:

  • \(x_0\ y_0\ x_1\ y_1\ c\),对\(a[x][y],x\in[x_0,x_1],y\in[y_0,y_1]\)异或上一个数\(c\)
  • \(x_0\ y_0\ x_1\ y_1\),询问这个子矩阵的异或和

\(n\le 1000,m\le 10^5,0\le c<2^{62}\)

分析

树状数组的妙用!关键还是在异或的性质和处理矩阵的方法。

首先考虑矩阵异或,单点查询,那么对于一个修改\((x_0,y_0,x_1,y_1,c)\),如果我们对\((x_0,y_0),(x_0,y_1+1),(x_1+1,y_0),(x_1+1,y_1+1)\)都异或上\(c\),那么一个结论就是一个点\((x,y)\)的值就是\((1,1,x,y)\)的异或和。(画一画图就知道了)

现在是询问子矩阵的异或和,显然首先转化为求任意的\((1,1,x,y)\)的异或和。

在之前那种修改方式下,一个点的点值就是\((1,1,x,y)\)的异或和,那么要求\((1,1,x,y)\)的异或和,我们就把这些异或和异或起来。

考虑每个点的出现次数,我们会发现,对于一个点\((x_0,y_0)\),它在总异或中出现奇数次当且仅当\((x-x_0+1)(y-y_0+1)\)为奇数。

例如我们统计\((1,1,3,4)\)的异或和的异或和,我们只用统计\((1,2),(1,4),(3,2),(3,4)\)这几个点的值。

于是对于每一种\((x,y)\)的奇偶情况,我们开一个二维树状数组来进行单点修改,前缀异或和查询即可(二维树状数组就是一维树状数组的每个点都是一个树状数组)。

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
int read() {
	int x=0,f=1;
	char c=getchar();
	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
const int maxn=1e3+2;
int n,m;
inline int lowbit(int x) {return x&-x;}
struct BIT {
	giant c[maxn][maxn];
	void change(int x,int y,giant d) {
		for (;x<=n+1;x+=lowbit(x)) for (int i=y;i<=n+1;i+=lowbit(i)) c[x][i]^=d;
	}
	giant query(int x,int y) {
		giant ret=0;
		for (;x;x-=lowbit(x)) for (int i=y;i;i-=lowbit(i)) ret^=c[x][i];
		return ret;
	}
} t[2][2];
giant get(int x,int y) {
	giant ret=t[x&1][y&1].query((x+1)>>1,(y+1)>>1);
}
giant get(int x1,int y1,int x2,int y2) {
	giant a=get(x1-1,y1-1);
	giant b=get(x1-1,y2);
	giant c=get(x2,y1-1);
	giant d=get(x2,y2);
	giant ret=a^b^c^d;
	return ret;
}
void change(int x,int y,giant c) {
	t[x&1][y&1].change((x+1)>>1,(y+1)>>1,c);
}
void change(int x1,int y1,int x2,int y2,giant c) {
	change(x1,y1,c);
	change(x1,y2+1,c);
	change(x2+1,y1,c);
	change(x2+1,y2+1,c);
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
#endif
	n=read(),m=read();
	while (m--) {
		int o=read(),x1=read(),y1=read(),x2=read(),y2=read();
		giant c;
		if (o==2) scanf("%lld",&c);
		if (o==1) printf("%lld\n",get(x1,y1,x2,y2)); else change(x1,y1,x2,y2,c);
	}
	return 0;
}
posted @ 2017-07-11 20:35  permui  阅读(394)  评论(0编辑  收藏  举报