题意:给出一个n*m的矩阵,矩阵上每个点有一种植物,有T次操作,对于每次操作给出两个殿P1,P2,v,要求给以P1为左上角以P2为右下角的子矩阵中每个植物施种类为v的化肥,如果化肥种类和植物种类不一样,这该点的植物会立马死亡,求T次操作结束之后死亡的植物数量。
这题比赛时没想到解题方法,赛后看题解大概有三种解法:
一:二维树状数组
二:线段树+扫瞄线
三:随机化算法
这里先给出我觉得的最玄学的随机化算法,前两种写法后续更新。
由于题目中n*m<=1e6,种类<=1e6,所以对于每个种类可以给它随机化一个[1e6,1e7]的权值b[i],然后修改操作便是给对应区间加上要施的肥料种类对应的随机化值,最后计算出每个点最后总的改变值cnt(i,j),如果cnt(i,j)%b(a(i,j))!=0,则该点的植物有极大的可能是死亡的。对于每个格子,如果权值为p,则该点这种做法的正确率为(p-1)/p。
这题没有给出n和m的具体范围,所以只能用vector了。
/*************************************************************************
> File Name: nkdx2-J.cpp
> Author: cyh
> Mail:
> Created Time: 2018年07月22日 星期日 18时44分42秒
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll tree[rt].l
#define rr tree[rt].r
#define rs rt<<1|1
#define ls rt<<1
const int maxn=1e6+10;
const int inf=1e9+10;
const long long INF=2e18+10;
int n,m,t;
vector<LL> b,cnt[maxn];
vector<int> a[maxn];
LL Rand(){return (1ll*rand()<<15)+rand();}
int main()
{
scanf("%d%d%d",&n,&m,&t);
srand(233);
b.push_back(0ll);
for(int i=1;i<=n*m;i++) b.push_back(0ll),b[i]=Rand();
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
a[i].push_back(0);
cnt[i].push_back(0ll);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
int x1,y1,x2,y2,c;
for(int i=1;i<=t;i++){
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
cnt[x1][y1]+=b[c];
cnt[x2+1][y2+1]+=b[c];
cnt[x2+1][y1]-=b[c];
cnt[x1][y2+1]-=b[c];
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cnt[i][j]+=cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1];
if(cnt[i][j]%(b[a[i][j]])) ans++;
}
}
printf("%d\n",ans);
return 0;
}
更新~~~~~~~~~~
此题另一种解法,对于每一个数,数据范围为[1,1e6],二进制最多20位,所以我们可以看每个数每一位的变化,复杂度大概1e7,因为对于每个数如果后来变成了不同的数,至少有一个二进制位与原来的数不同。其实这两种解法的更新部分都与二维树状数组类似。
AC代码:
/*************************************************************************
> File Name: nkdx2-J题2.cpp
> Author: cyh
> Mail:
> Created Time: 2018年07月23日 星期一 09时03分54秒
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll tree[rt].l
#define rr tree[rt].r
#define rs rt<<1|1
#define ls rt<<1
const int maxn=2e6+10;
const int inf=1e9+10;
const long long INF=2e18+10;
int a[maxn],cnt[maxn][2],vis[maxn];
int n,m,T;
inline int f(int x,int y){return x*m+y;}
struct node{int x1,y1,x2,y2,c;}Q[maxn];
int main()
{
scanf("%d%d%d",&n,&m,&T);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
scanf("%d",&a[f(i,j)]);
}
for(int i=1;i<=T;i++) scanf("%d%d%d%d%d",&Q[i].x1,&Q[i].y1,&Q[i].x2,&Q[i].y2,&Q[i].c);
int ans=0;
for(int v=0;v<=20;v++){
for(int i=1;i<=T;i++){
int x1=Q[i].x1,y1=Q[i].y1,x2=Q[i].x2,y2=Q[i].y2,c=Q[i].c;
cnt[f(x1,y1)][(c>>v)&1]++;
cnt[f(x2+1,y2+1)][(c>>v)&1]++;
cnt[f(x1,y2+1)][(c>>v)&1]--;
cnt[f(x2+1,y1)][(c>>v)&1]--;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cnt[f(i,j)][0]+=cnt[f(i-1,j)][0]+cnt[f(i,j-1)][0]-cnt[f(i-1,j-1)][0];
cnt[f(i,j)][1]+=cnt[f(i-1,j)][1]+cnt[f(i,j-1)][1]-cnt[f(i-1,j-1)][1];
if(!vis[f(i,j)]&&cnt[f(i,j)][((a[f(i,j)]>>v)&1)^1]) ans++,vis[f(i,j)]=1;
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cnt[f(i,j)][0]=cnt[f(i,j)][1]=0;
}
printf("%d\n",ans);
return 0;
}