题干:
小a正在玩一款即时战略游戏,现在他要用航空母舰对敌方阵地进行轰炸
地方阵地可以看做是n×mn×m的矩形
航空母舰总共会派出qq架飞机。
飞机有两种,第一种飞机会轰炸以(xi,yi)(xi,yi)为中心,对角线长为lili的正菱形(也就是两条对角线分别于xx轴 yy轴平行的正方形),而第二种飞机只会轰炸正菱形的上半部分(包括第xixi行)
(具体看样例解释)
现在小a想知道所有格子被轰炸次数的异或和
注意:不保证被轰炸的格子一定在矩形范围内,若越界请忽略
输入描述:
第一行三个整数n,m,qn,m,q,分别表示矩阵的长/宽/询问次数 接下来qq行,每行四个整数opt,x,y,lopt,x,y,l,表示飞机类型,轰炸的坐标,以及对角线长度 保证ll为奇数!
输出描述:
一个整数,表示所有格子被轰炸次数的异或和
示例1
输入
4 5 4 1 2 2 1 1 3 3 5 1 3 2 3 2 2 4 3
输出
2
说明
每次的操作矩阵即操作后的矩阵的值如下
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 2 1 1 0
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
0 3 1 1 0
2 2 2 1 1
0 2 1 1 0
0 0 1 1 0
0 3 2 2 1
2 2 2 1 1
0 2 1 1 0
最后把所有元素异或后为2
备注:
1⩽n,m⩽10001⩽n,m⩽1000
1⩽q⩽5∗1051⩽q⩽5∗105
保证opt=1/2,1⩽x,y,l⩽max(N,M)opt=1/2,1⩽x,y,l⩽max(N,M)
读入文件过大,请使用较快的读入方式
解题报告:
这题考查的是对差分数组和前缀和的理解。四个数组分别记录朝着四个方向下放的个数最后求个前缀,就代表着这一行中从这个点开始作为起点的轰炸区域个数,四个数组分别向着四个方向下放最终得到的四个数组分别是前。可以找个边长为1的操作模拟一下,虽然看着别扭但是没啥问题。也就是:数组中是差分数组,最后查询是前缀和查询。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 3030,ADD = 1000;
int a[MAX][MAX],b[MAX][MAX],c[MAX][MAX],d[MAX][MAX];
void up(int x,int y,int l) {
a[x-l/2][y]++,b[x-l/2][y+1]--;
a[x+1][y-l/2-1]--,b[x+1][y+l/2+2]++;
}
void down(int x,int y,int l){
c[x+1][y-l/2+1]++,d[x+1][y+l/2]--;
c[x+l/2+1][y+1]--,d[x+l/2+1][y]++;
}
int main() {
int n,m,q;
cin>>n>>m>>q;
for(int op,x,y,l,i = 1; i<=q; i++) {
scanf("%d%d%d%d",&op,&x,&y,&l);
x+=ADD,y+=ADD;
if(op == 1) up(x,y,l),down(x,y,l);
if(op == 2) up(x,y,l);
}
for(int i = 1; i<=n+ADD*2; i++) {
for(int j = 1; j<=m+ADD*2; j++) {
a[i][j] += a[i-1][j+1];
b[i][j] += b[i-1][j-1];
c[i][j] += c[i-1][j-1];
d[i][j] += d[i-1][j+1];
}
}
int ans = 0;
for(int i = 1; i<=n+ADD*2; i++) {
int tmp = 0;
for(int j = 1; j<=m+ADD*2; j++) {
tmp += a[i][j] + b[i][j] + c[i][j] + d[i][j];
if(i>=ADD+1 && i<=ADD+n && j>=ADD+1 && j<=ADD+m) ans ^=tmp;
}
}
cout << ans <<endl;
return 0 ;
}