Description
给一个 n×m n × m 的矩阵 ai,j a i , j , T T 次操作,每次操作把一个子矩阵中不等于 k k 的数字删掉,一个数字只会被删掉一次,问操作结束后该矩阵中被删掉的数字个数
Input
第一行一整数,之后输入一个 n×m n × m 矩阵,最后 T T 行每行输入五个整数
(n⋅m≤106,T≤106,1≤ai,j,k≤n⋅m) ( n ⋅ m ≤ 10 6 , T ≤ 10 6 , 1 ≤ a i , j , k ≤ n ⋅ m )
Output
输出被删掉的数字个数
Sample Input
2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1
Sample Output
3
Solution
考虑数字只有 0,1 0 , 1 的情况,只需用二维前缀和维护一个位置被加的 1 1 的数量和的数量,如果该位置为 x x 且被加入的数量非 0 0 则该位置记入答案,而对于数字不超过的情况,分 29 29 位分别考虑即可,只要有一位有变动则该位置的值发生变化
Code
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 1000005
int n,m,T,g[maxn],first[maxn],tot[maxn],a1[maxn],b1[maxn],a2[maxn],b2[maxn],k[maxn],vis[maxn];
int ID(int x,int y)
{
if(x==0||y==0)return 0;
return (x-1)*m+y;
}
void update(int a1,int b1,int a2,int b2,int *a)
{
a[ID(a1,b1)]++;
if(b2<m)a[ID(a1,b2+1)]--;
if(a2<n)a[ID(a2+1,b1)]--;
if(b2<m&&a2<n)a[ID(a2+1,b2+1)]++;
}
void sum(int *a)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[ID(i,j)]+=(a[ID(i-1,j)]+a[ID(i,j-1)]-a[ID(i-1,j-1)]);
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&T))
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&g[ID(i,j)]);
memset(tot,0,sizeof(tot));
for(int i=1;i<=T;i++)
{
scanf("%d%d%d%d%d",&a1[i],&b1[i],&a2[i],&b2[i],&k[i]);
update(a1[i],b1[i],a2[i],b2[i],tot);
}
sum(tot);
memset(vis,0,sizeof(vis));
for(int s=0;s<20;s++)
{
memset(first,0,sizeof(first));
for(int i=1;i<=T;i++)
if((k[i]>>s)&1)
update(a1[i],b1[i],a2[i],b2[i],first);
sum(first);
for(int i=1;i<=n*m;i++)
if((g[i]>>s)&1)
{
if(first[i]!=tot[i])vis[i]=1;
}
else if(first[i])vis[i]=1;
}
int ans=0;
for(int i=1;i<=n*m;i++)ans+=vis[i];
printf("%d\n",ans);
}
return 0;
}