https://ac.nowcoder.com/acm/problem/16637
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
const int maxn=1e6+2;
const int mod=1e9+7;
typedef long long ll;
//思路:我们重新给每种化肥安排序号,尽可能的不让其之间有倍数的关系,这样的话,q次施肥之后如果当前位置的所有肥料之和是当前植物序号(也就是我们重新分配的序号)的倍数,那么当前植物不会死亡。
//本题思路: 写一个random的hash,表达里边数唯一。
//给区域加编号k的化肥操作:是让该区域都加上hash[k]
//若编号k植物格子,查询到值为hash[k]的整数倍,那么说明这格子,只有第k种化肥施加过,如不是,则有其他化肥,那么该植物死亡,ans++
ll has[maxn]; //每种化肥的映射,以防止同一区域内发生 3的整数倍不是加3加出来的,而是同时加1,加2加出来的
int main(){
int n,m,t,x1,x2,y1,y2,k;
cin>>n>>m>>t;
//对hash初始化(重新编号)
srand(time(0));
for(int i=1;i<=n*m;i++)
has[i]=(ll)i*rand()+maxn; //数越大,越不容易重复
//用的二维动态数组,把a[i][j]记录原值,而b[i][j]则记录加上每次的化肥。
//动态数组初始化
ll **a=new ll*[n+10];
ll **dp=new ll*[n+10];
for(int i=0;i<=n+1;i++){ //动态数组必须初始化为0 (为什么到n+1)防止后面修改越界,不需要加if了
a[i]=new ll[m+2];
dp[i]=new ll[m+2];
for(int j=0;j<=m+1;j++){
a[i][j]=dp[i][j]=0;
if(i>0&&i<=n&&j>0&&j<=m)cin>>a[i][j],a[i][j]=has[a[i][j]];
}
}
while(t--){
cin>>x1>>y1>>x2>>y2>>k;
ll tmp=has[k];
//根据定义一维差分bi=ai-ai-1
//若修改ai一个区间的值,只修改bl(+k)和br+1(-k)。
//拓展到二维差分b(i,j)=a(i,j)-a(i-1,j)-a(i,j-1)+a(i-1,j-1)
//若修改a(i,j)一个区域的值,只修改 行的l,r+1,列的l,r+1,中这四个数组合成的四个坐标点。若(l|r+1,l|r+1)为正,(l|r+1,r+1|l)为负
//下面代码作用:此时dp为bi,(修改一个区域的值)
dp[x1][y1]+=tmp;
dp[x1][y2+1]-=tmp;
dp[x2+1][y1]-=tmp;
dp[x2+1][y2+1]+=tmp;
}
ll ans=0;
for(int i=1;i<=n;i++){ //查询是否为hash[k]的整数倍,不是则+1
for(int j=1;j<=m;j++){
dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]; //此时dp为ai
if(dp[i][j]%a[i][j])
ans++;
}
}
cout<<ans;
}