Description
给出一个n×nn×n的矩阵,有5050种动物,初始时矩阵每个位置都没有动物,mm次操作,操作分两种
:在子矩阵[x1,x2]×[y1,y2][x1,x2]×[y1,y2]的每个位置放bibi个第aiai种动物
Q x1 y1 x2 y2:Q x1 y1 x2 y2:查询子矩阵[x1,x2]×[y1,y2][x1,x2]×[y1,y2]所有位置这5050种动物数量之和的奇偶性
Input
第一行输入两个整数n,mn,m表示矩阵维数和查询数,之后mm行每行一组查询
Output
对于每组查询输出5050个整数,第ii个整数表示子矩阵中第种动物数量之和的奇偶性(奇数输出22,偶数输出)
Sample Input
2 2
P 1 1 2 2 1 1 1
Q 1 1 1 1
Sample Output
2 1 …. 1
Solution
把五十种动物的奇偶性用5050位0101压成一个状态,每次加入偶数的动物显然对答案没影响,加入奇数个动物等价于加入一个动物,子矩阵动物数量之和的奇偶性等价于每个位置该种动物数量奇偶性的异或和
首先看一维情况,即区间异或的操作和区间异或和的查询,由树状数组可以把这两种操作变成单点修改和前缀异或和查询,如果对区间[L,R][L,R]进行异或xx的操作,考虑该次操作对前缀异或和的影响,显然如果yy和奇偶性相同那么影响为xx,否则影响为,而该区间异或xx的操作在实现时是对位置异或xx,并对位置异或xx以消除对后面值的影响,故如果单点修改位置为奇数,那么该次修改只对该位置及其之后的奇数位置的前缀异或和有影响,偶数同理,那么如果直接把普通的树状数组的加法改成异或显然是不对的,因为对于一个偶数位置的前缀和,其前面奇数位置的修改也会被统计到,为避免这种情况,再加一维表示修改查询位置的奇偶性,把奇偶性不同的修改查询位置分成两个树状数组分别处理
对于二维情况,只需对一维情况做推广,对子矩阵的修改变成对(x1,y1),(x1,y2+1),(x2+1,y1),(x2+1,y2+1)(x1,y1),(x1,y2+1),(x2+1,y1),(x2+1,y2+1)四个顶点的修改,对该子矩阵的查询也变成对以这四个顶点为右下角,(1,1)(1,1)位左上角的前缀子矩阵查询,每次修改点(x,y)(x,y)的值以及查询[1,x]×[1,y][1,x]×[1,y]的前缀异或和时,要根据x,yx,y奇偶性的不同分到四个树状数组中分别处理
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 3210
int n,m;
ll f[55];
struct BIT
{
#define lowbit(x) (x&-x)
ll b[2][2][maxn][maxn];
void init()
{
memset(b,0,sizeof(b));
}
void update(int x,int y,ll v)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=n;j+=lowbit(j))
b[x&1][y&1][i][j]^=v;
}
ll query(int x,int y)
{
ll ans=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
ans^=b[x&1][y&1][i][j];
return ans;
}
}bit;
void Update(int x1,int y1,int x2,int y2,ll v)
{
bit.update(x2,y2,v);
bit.update(x1,y1,v);
bit.update(x1,y2,v);
bit.update(x2,y1,v);
}
void Query(int x1,int y1,int x2,int y2)
{
ll ans=bit.query(x2,y2)^bit.query(x1,y1)^bit.query(x1,y2)^bit.query(x2,y1);
for(int i=1;i<=50;i++)
if(ans&f[i])printf("2 ");
else printf("1 ");
printf("\n");
}
int main()
{
f[1]=2;
for(int i=2;i<=50;i++)f[i]=2ll*f[i-1];
while(~scanf("%d%d",&n,&m))
{
bit.init();
while(m--)
{
char op[11];
int x1,y1,x2,y2,k,kind,num;
ll temp;
scanf(" %s%d%d%d%d",op,&x1,&y1,&x2,&y2);
if(op[0]=='P')
{
scanf("%d",&k);
temp=0;
while(k--)
{
scanf("%d%d",&kind,&num);
if(num&1)temp^=f[kind];
}
Update(x1,y1,x2+1,y2+1,temp);
}
else Query(x1-1,y1-1,x2,y2);
}
}
return 0;
}