题目描述
有消息称:绝恋找到了自己的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。
分别为矩形横坐标中的最小值和最大值,为矩形纵坐标中的最小值和最大值。
输出格式
对于每一个操作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
思路:
直接暴力枚举的呢毫无疑问是会T的,因此我们考虑用树状数组这一快捷方法
这题也是一个很明显的二维树状数组,但,不同的是:树状数组求前缀和,这里由于需要查找某个数的个数,因此我们把前缀和改为一个数组,令这个数组的第i项表示数字i的个数,那么,树状数组就变为了一个三维的数组;
AC code:
#include<bits/stdc++.h>
using namespace std;
const int N=310;
int m,n,a,s[N][N],f[N][N][N];
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<=m;j+=lowbit(j)){
f[i][j][past]--;//记得原始数据减一
f[i][j][now]++;
}
}
int sum(int x,int y,int z){//求f个数
int res=0;
for(int i=x;i>0;i-=lowbit(i))
for(int j=y;j>0;j-=lowbit(j)){
res+=f[i][j][z];
}
return res;
}
int find(int x1,int x2,int y1,int y2,int z){
int ans=0;
ans=sum(x1-1,y1-1,z)+sum(x2,y2,z)-sum(x1-1,y2,z)-sum(x2,y1-1,z);//前缀和
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&s[i][j]);
add(i,j,0,s[i][j]);
}
scanf("%d",&a);
int k,c;
for(int i=1;i<=a;i++){
scanf("%d",&k);
if(k==1){
int x,y;
scanf("%d%d%d",&x,&y,&c);
int p=s[x][y];
s[x][y]=c;
add(x,y,p,c);
}
if(k==2){
int x1,y1,x2,y2;
scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&c);
int tot=find(x1,x2,y1,y2,c);
printf("%d\n",tot);
}
}
return 0;
}
如有错误,欢迎大佬们在评论区指正~
#一名爱玩狂铁的oier#
标签:树状,int,情书,密码,数组,绝恋 From: https://www.cnblogs.com/hzoiwzs/p/18023742