题目大意: 给出一个n*m的矩阵农场, G[i][j]代表着对应植物所需的肥料类型, 有T组操作, 对第i个操作是对子矩阵G[x1[i]…x2[i]][y1[i]…y2[i]]施以肥料k[i], 若植物得到了错误的肥料会死亡。 求T组操作后死亡的植物总数。 (n∗m≤106,G[i][j],k[i]≤106) ( n ∗ m ≤ 10 6 , G [ i ] [ j ] , k [ i ] ≤ 10 6 )
题目思路: 先考虑一种简单的情况, 如果只有0和1这两种, 那么可以直接用二维的差分来维护各个施肥。 即对于第i个操作, f[x1[i]][y1[i]]++, f[x2[i]+1][y1[i]]–, f[x1[i]][y2[i]]–, f[x2[i]+1][y2[i]+1]++, 最后求一遍矩阵前缀和求可以求出各个植物被施肥的次数, 分别对肥料1和肥料0都这么做, 则一个植物会产生贡献就是与其相反的肥料施肥次数大于0。 最后考虑整个题目, 可以枚举各个二进制位, 考虑两个数不同则至少有一个二进制位上是不同的, 同样按照01情况维护即可。
Code:
#include <map>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define id(i, j) (m * ((i) - 1) + (j))
const int N = (int)1e6 + 10;
int n, m, T;
int G[N], x1[N], x2[N], Y1[N], y2[N], v[N], ans[N];
int f[N][2];
int main(){
scanf("%d %d %d", &n, &m, &T);
for (int i = 1; i <= n * m; i ++)
scanf("%d", G + i);
for (int i = 1; i <= T; i ++)
scanf("%d %d %d %d %d", x1 + i, Y1 + i, x2 + i, y2 + i, v + i);
for (int h = 0; h < 20; h ++){
memset(f, 0, sizeof(f));
for (int i = 1; i <= T; i ++){
f[id(x1[i], Y1[i])][(v[i] >> h) & 1] ++;
if (x2[i] < n) f[id(x2[i] + 1, Y1[i])][(v[i] >> h) & 1] --;
if (y2[i] < m) f[id(x1[i], y2[i] + 1)][(v[i] >> h) & 1] --;
if (x2[i] < n && y2[i] < m) f[id(x2[i] + 1, y2[i] + 1)][(v[i] >> h) & 1] ++;
}
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++){
for (int k = 0; k <= 1; k ++){
if (j > 1) f[id(i, j)][k] += f[id(i, j - 1)][k];
if (i > 1) f[id(i, j)][k] += f[id(i - 1, j)][k];
if (i > 1 && j > 1) f[id(i, j)][k] -= f[id(i - 1, j - 1)][k];
}
if ((G[id(i, j)] >> h) & 1) ans[id(i, j)] |= (f[id(i, j)][0] > 0);
else ans[id(i, j)] |= (f[id(i, j)][1] > 0);
}
}
for (int i = 1; i <= n * m; i ++)
ans[i] += ans[i - 1];
printf("%d", ans[n * m]);
return 0;
}