题面:
题意:
给定一个矩阵,有两种操作,(1)修改一个格子的颜色(2)查询一个矩阵中颜色为C的格子的数量
分析:
注意到颜色<100,如果是一维,我们可以对每个C建一个树状数组,维护它出现的位置;对于二维,用二维树状数组:在一维树状数组中tr[x]表示以x为右端点长度为lowbit[x]的区间的信息,对于二维树状数组tr[x][y]表示以(x,y)为右下角,高为lowbit(x),宽为lowbit(y)的矩阵的信息,只需要在一维每个区间的基础上再建一个关于y的树状数组即可;查询某个子矩阵的信息时,和二维前缀和查询子矩阵的和的方法一样,例如查询左上角为(x,y),右下角为(xx,yy)的矩阵的和:sum[xx][yy] - sum[xx][y-1] - sum[x-1][yy]+sum[x-1][y-1]
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 305;
int tr[105][maxn][maxn],color[maxn][maxn],n,m,q,x,y,xx,yy,op,c;
inline int lowbit(int x){
return (-x)&x;
}
int query(int x,int y,int c){ //查询左上角为(1,1)右下角为(x,y)的矩阵的信息
int sum = 0;
for(int i = x;i > 0;i -= lowbit(i))
for(int j = y;j > 0;j -= lowbit(j))
sum += tr[c][i][j];
return sum;
}
void updata(int x,int y,int c,int val){ //更新坐标为(x,y)格子的信息
for(int i = x;i <= n;i += lowbit(i))
for(int j = y; j <= m;j += lowbit(j))
tr[c][i][j] += val;
}
int main(){
scanf("%d %d",&n,&m);
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= m; ++j)
scanf("%d",&color[i][j]),updata(i,j,color[i][j],1);
scanf("%d",&q);
while(q--){
scanf("%d",&op);
if(op == 1){
scanf("%d %d %d",&x,&y,&c);
updata(x,y,color[x][y],-1);
color[x][y] = c;
updata(x,y,color[x][y],1);
}
else{
scanf("%d %d %d %d %d",&x,&xx,&y,&yy,&c);
printf("%d\n",query(xx,yy,c)+query(x-1,y-1,c)-query(xx,y-1,c)-query(x-1,yy,c));
}
}
return 0;
}