【JSOI2009】计数问题
题目链接
开颜色种类个二维树状数组,维护前缀和,单点修改、子矩阵查询。
注意读入的顺序,是$x_1\; x_2\; y_1\; y_2$而不是$x_1\; y_1\; x_2\; y_2$。
代码(100分):
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<map> #include<set> #define IL inline #define RG register #define _1 first #define _2 second using namespace std; const int N=300; const int M=100; int n,m,q,a[N+3][N+3]; int s[M+3][N+3][N+3]; IL int lowbit(int x){ return x&(-x); } IL void mdfm(int k,int p,int q,int x){ for(;q<=m;q+=lowbit(q)) s[k][p][q]+=x; } IL void mdfn(int k,int p,int q,int x){ for(;p<=n;p+=lowbit(p)) mdfm(k,p,q,x); } IL int qrym(int k,int p,int q){ int ret=0; for(;q;q-=lowbit(q)) ret+=s[k][p][q]; return ret; } IL int qryn(int k,int p,int q){ int ret=0; for(;p;p-=lowbit(p)) ret+=qrym(k,p,q); return ret; } IL int qry(int x1,int y1,int x2,int y2,int c){ return qryn(c,x2,y2)-qryn(c,x1-1,y2)-qryn(c,x2,y1-1)+qryn(c,x1-1,y1-1); } IL void dat_init(){ memset(s,0,sizeof s); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); dat_init(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) mdfn(a[i][j],i,j,1); scanf("%d",&q); while(q--){ int opt; scanf("%d",&opt); if(opt==1){ int x,y,c; scanf("%d%d%d",&x,&y,&c); mdfn(a[x][y],x,y,-1); mdfn(c,x,y,1); a[x][y]=c; } else { int x1,x2,y1,y2,c; scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&c); printf("%d\n",qry(x1,y1,x2,y2,c)); } } return 0; }