克拉克是一名人格分裂患者。某一天,有两个克拉克(aa和bb)在玩一个方格游戏。
这个方格是一个nmn∗m的矩阵,每个格子里有一个数cijci,j。
aa想开挂,想知道如何打败bb。
他们要玩qq次游戏,每一次做一次操作:
1. 取出当中的一个子矩阵x1y1x2y2(x1,y1)−(x2,y2)玩游戏。两个人轮流行动,每一次只能从这个子矩阵中的一个方格cijci,j中减掉一个的数d1dcijd(1≤d≤ci,j),当一个格子的数为00时则不能减。如果操作完后另一者无法操作,那么胜利。否则失败。现在aa作为先手,想知道是否存在一种方案使得自己胜利。
2. 将cijci,j的数改成bb
输入描述
第一行一个整数T1T5T(1≤T≤5),表示数据的组数。
每组数据第一行为三个整数nmq1nm5001q2105n,m,q(1≤n,m≤500,1≤q≤2∗105)。
接下来是一个nn行mm列的矩阵,其中第ii行第jj列的数为cij0cij109ci,j(0≤ci,j≤109)。
接下来时qq行,第一个数为optopt。当opt1opt=1时,后面接着四个整数,依次表示x1y1x2y21x1x2n1y1y2mx1,y1,x2,y2(1≤x1≤x2≤n,1≤y1≤y2≤m),表示一个询问;当opt2opt=2时,后面接着三个整数xyz1xn1ym0z109x,y,z(1≤x≤n,1≤y≤m,0≤z≤109),表示将cxycx,y更改为zz。
输出描述
对于每组数据,每个询问输出aa是否能胜利,如果能,输出YesYes,否则输出NoNo。
输入样例
1
1 2 3
1 2
1 1 1 1 2
2 1 2 1
1 1 1 1 2
输出样例
Yes
No
Hint
第一个询问:一开始aa可以在12(1,2)的格子上减掉11,则接下来无论bb怎么选,都还剩一个11,所以aa胜利。
第二个询问:无论aa怎么选,都还剩下一个11,所以bb胜利。
题目要求二维的nim游戏,考虑到nim的结论是xor和为0则必败、否则必胜,那么我们只需要维护子矩阵的xor和。由于xor有前缀和性质,所以我们可以用一个二维bit来维护(1, 1)-(a, b)的矩阵的xor和,然后由sumx2y2 xor sumx2y11 xor sumx11y2 xor sumx11y11sum(x2,y2) xor sum(x2,y1−1) xor sum(x1−1,y2) xor sum(x1−1,y1−1)来得到答案即可。单点修改在bit上是很容易的。
#include <cstdio>
#include <cstring>
using namespace std;
int T, n, m, q;
int c[600][600];
int num[600][600];
int lowbit(int x)
{
return x & (-x);
}
int query(int x, int y)
{
int ret = 0;
for (int i = x; i > 0; i -= lowbit(i))
{
for (int j = y; j > 0; j -= lowbit(j))
{
ret ^= c[i][j];
}
}
return ret;
}
void modify(int x, int y, int delta)
{
for (int i = x; i <= n; i += lowbit(i))
{
for (int j = y; j <= m; j += lowbit(j))
{
c[i][j] ^= delta;
}
}
}
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d%d%d", &n, &m, &q);
memset(num, 0, sizeof(num));
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
scanf("%d", &num[i][j]);
modify(i, j, num[i][j]);
}
int opt, x1, y1, x2, y2;
int x, y, z;
for (int i = 1; i <= q; i++)
{
scanf("%d", &opt);
if (opt == 1)
{
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int ans = query(x2, y2) ^ query(x1 - 1, y1 - 1) ^ query(x2, y1 - 1) ^ query(x1 - 1, y2);
//printf("<%d>\n", ans);
if (ans == 0)
printf("No\n");
else
printf("Yes\n");
}
else
{
scanf("%d%d%d", &x, &y, &z);
modify(x, y, z ^ num[x][y]);
num[x][y] = z;
}
}
}
return 0;
}