[JSOI2009]计数问题
Posted 天下风云出我辈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JSOI2009]计数问题相关的知识,希望对你有一定的参考价值。
一个n*m的方格,初始时每个格子有一个整数权值。接下来每次有2种操作: 改变一个格子的权值; 求一个子矩阵中某种特定权值出现的个数。 输入输出格式 输入格式: 第一行有两个数N,M。 接下来N行,每行M个数,第i+1行第j个数表示格子(i,j)的初始权值。 接下来输入一个整数Q。 之后Q行,每行描述一个操作。 操作1:“1 x y c”(不含双引号)。表示将格子(x,y)的权值改成c(1<=x<=n,1<=y<=m,1<=c<=100)。 操作2:“2 x1 x2 y1 y2 c”(不含双引号,x1<=x2,y1<=y2)。表示询问所有满足格子颜色为c,且x1<=x<=x2,y1<=y<=y2的格子(x,y)的个数。 输出格式: 对于每个操作2,按照在输入中出现的顺序,依次输出一行一个整数表示所求得的个数。
二维的点修改,区间查询,所以树状数组当然没得跑啦,二维的和一维的写法是一样的,只是传参的时候多传几个,循环的时候是2层循环而已,然后当然是权值树状数组开桶来记录个数啦。有一个需要注意的地方是,这里因为查询的是某个子矩阵中的某个数的个数,所以和一维的有一点不一样,这里需要像计算二维前缀和一样,先加一大块,再减两小块,在加上重复减的那个小小块。我会说我开始就是这里写错了吗
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int n,m,t,q,x,y,xx,yy,w,c[105][305][305],a[305][305]; 6 void update(int d,int x,int y,int w) 7 { for(int i=x;i<=n;i+=i&-i) 8 for(int j=y;j<=m;j+=j&-j) 9 c[d][i][j]+=w; 10 } 11 int query(int d,int x,int y) 12 { int ans=0; 13 for(int i=x;i>0;i-=i&-i) 14 for(int j=y;j>0;j-=j&-j) 15 ans+=c[d][i][j]; 16 return ans; 17 } 18 int main() 19 { freopen("count.in","r",stdin); 20 freopen("count.out","w",stdout); 21 scanf("%d%d",&n,&m); 22 memset(c,0,sizeof c); 23 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) 24 { scanf("%d",&a[i][j]); 25 update(a[i][j],i,j,1); 26 } 27 scanf("%d",&q); 28 for(int i=1;i<=q;i++) 29 { scanf("%d",&t); 30 if(t==1) 31 { scanf("%d%d%d",&x,&y,&w); 32 update(a[x][y],x,y,-1); 33 update(w,x,y,1); 34 a[x][y]=w; 35 }else 36 { scanf("%d%d%d%d%d",&x,&xx,&y,&yy,&w); 37 int ans=query(w,xx,yy)-query(w,x-1,yy)-query(w,xx,y-1)+query(w,x-1,y-1); 38 printf("%d\n",ans); 39 } 40 } 41 return 0; 42 }
以上是关于[JSOI2009]计数问题的主要内容,如果未能解决你的问题,请参考以下文章