题目链接:传送门
题目大意:
有一个n*m的矩形,每个位置有一个数。有T次操作,每次往一个子矩形的每个格子中放入一个数。
求有多少个格子中被放入了至少一个与对应位置不相同的数。
n*m<=1e6,T<=1e6
题目思路:
每次放入一个数,如果操作若干次后,将放入的所有数相加除以对应位置的数,如果整除则放入的数和对应的位置数相同。这是一个不充分但必要条件。
即可能会出现一些特殊情况,比如放入了1,2,但相应位置的数为3则结果时符合,但是与事实不符。
所以我们用hash的方法,减少这种特殊的情况,当放入的数和相应的位置的数足够大的时候,这种概率就会被无限的缩小。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
struct BIT_2D
{
int n,m;
vector<ll> C[maxn];
int lowbit(int x){return x&(-x);}
void init(int n,int m) //初始化n行m列矩阵
{
this->n=n;
this->m=m;
for(int i=1;i<=n;i++)
{
C[i].clear();
for(int j=0;j<=m;j++) C[i].push_back(0);
}
}
void add(int x,int y,ll val)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j)) C[i][j]+=val;
}
void range_add(int x1,int y1,int x2,int y2,ll x) //左上角为(x1,y1)右下角为(x2,y2)的矩阵全部加上x
{
add(x1,y1,x);
add(x1,y2+1,-x);
add(x2+1,y1,-x);
add(x2+1,y2+1,x);
}
ll ask(int x,int y) //查询点(x,y)的值
{
ll 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;
}
}BIT;
int n,m,T;
vector<ll> a[maxn];
ll has[maxn];
inline ll get_rand(int m,int n)
{
return rand()%(n-m+1)+m;
}
void myhash(int m)
{
srand(time(NULL));
for(int i=1;i<=m;i++) has[i]=get_rand(1e6,9e6);
}
int main()
{
scanf("%d%d%d",&n,&m,&T);
myhash(n*m);
BIT.init(n,m);
for(int i=1;i<=n;i++)
{
a[i].clear(); a[i].push_back(0);
for(int j=1,type;j<=m;j++)
{
scanf("%d",&type);
a[i].push_back(has[type]);
}
}
for(int i=1;i<=T;i++)
{
int x1,y1,x2,y2,k;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
BIT.range_add(x1,y1,x2,y2,has[k]);
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(BIT.ask(i,j)%a[i][j] != 0) ans++;
}
}
cout<<ans<<endl;
}
/*
2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1
3
*/