题目
问题描述
有消息称:绝恋找到了自己的Miss Right,正准备自己的表白。绝恋已经写好了情书,但为了避免其它人截获,他对情书进行加密。
为了打探绝恋的私密,你冒着生命危险终于搞到了这封情书。原以为可以轻易将情书解密,结果竟然发现聪明的绝恋并没有直接写出加密用的密码,而是在那粉红色的信纸背面写着“T=你的幸运数字”。
就这么放弃了吗?不,作为一个高智商的OIer,你决不轻言放弃。你还搞到了绝恋做密码时的草稿,通过一定的分析,你发现草稿中隐藏了绝恋的密码,具体规则如下:
草稿纸上写着一个N*M 的矩阵,每个位置都有一个数字C,绝恋对该矩阵不断进行操作,有时会修改某一位置的值,还不时计算出一个矩形内特定数字的个数作为密码的一部分,绝恋十分聪明,他进行了许多次这样的操作,因此密码也异常复杂,但是你已经下定决心要算出密码了,所以你一定要算出来!!
输入格式:
第一行有两个数字N,M
接下来N 行,每行M 个数,第i+1 行第j 个数表示格子(i,j)的初始值。
接下来一个整数Q
接下来Q 行,每行描述一个操作
操作1:1 X Y C,表示将格子(X,Y)的权值改为C
操作2:2 X1 X2 Y1 Y2 C,表示询问矩形内有多少个位置的权值为C。X1 X2分别为矩形横坐标中的最小值和最大值,Y1 Y2为矩形纵坐标中的最小值和最大值。
输出格式:
对于每一个操作2,输出一个整数表示答案,每数一行。
样例输入:
3 3
1 2 3
3 2 1
2 1 3
3
2 1 2 1 2 1
1 2 3 2
2 2 3 2 3 2
样例输出:
1
2
数据范围:
对于30%的数据:1<=N,M<=30,Q<=50000
对于100%的数据:1<=N,M<=300,Q<=200000,C<=100
对于所有操作1:1<=X<=N,1<=Y<=M
对于所有操作2:1<=X1<=X2<=N,1<=Y1<=Y2<=M
思路
直接暴力枚举显然是不可能得满分的,因此我们可以换个思路:树状数组(如果你连树状数组都不知道是什么,那么打暴力当然是最明智的选择~(≧▽≦))
以下是暴力代码(引用自某位OIer)
代码君
#include<bits/stdc++.h>
using namespace std;
const int N=300+5;
int n,m,q,a[N][N];
int x,y,xx,yy,z,f;
int main(){
// freopen("test.in","r",stdin);
// freopen("test2.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
cin>>q;
while(q--){
cin>>f;
if(f==1){
cin>>x>>y>>z;
a[x][y]=z;
}
else{
cin>>x>>xx>>y>>yy>>z;
int ans=0;
for(int i=x;i<=xx;i++){
for(int j=y;j<=yy;j++){
if(a[i][j]==z)ans++;
}
}
cout<<ans<<endl;
}
}
return 0;
}
由于是一个矩阵,所以不难想到是一个二维树状数组。但不同的是,树状数组求的是前缀和,而本题需要查找某个指定数的个数,因此我们可以令加一个维度用来记录个数。
代码有注释哦~(^_−)☆
ACcode
代码君
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 0x3f
#define INF 0x3f3f3f3f
#define mst(a,b) memset(a,b,sizeof(a))
#define Elaina 0
const int N=305;
int a[N][N],c[N][N][N],n,m;//a[][]代表矩阵,存储原数据,c[][][]代表树状数组
int lowbit(int x){
return x&(-x);
}
void add(int x,int y,int past,int now){
for(int i=x;i<=N;i+=lowbit(i)){
for(int j=y;j<=N;j+=lowbit(j)){
c[i][j][past]--;//减去原数据
c[i][j][now]++;//加上现更新的数据
}
}
}
int getsum(int x,int y,int z){//指定数的个数
int sum=0;
for(int i=x;i>0;i-=lowbit(i)){
for(int j=y;j>0;j-=lowbit(j)){
sum+=c[i][j][z];
}
}
return sum;
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
add(i,j,0,a[i][j]);//将0改为输入数据
}
}
int t=0;
cin>>t;
while(t--){
int K;
cin>>K;
if(K==1){
int x,y,z;
cin>>x>>y>>z;
add(x,y,a[x][y],z);//将原数据改为更新的数据
a[x][y]=z;//原数组也要更新
}
if(K==2){
int x1,x2,y1,y2,z,sum=0;
cin>>x1>>x2>>y1>>y2>>z;
sum=getsum(x2,y2,z)-getsum(x1-1,y2,z)-getsum(x2,y1-1,z)+getsum(x1-1,y1-1,z);//二维前缀和计算公式
cout<<sum<<"\n";
}
}
return Elaina;
}
都看到这了,真的不点个赞吗(>ω<*)