BZOJ 1452: [JSOI2009]Count【树状数组】

1452: [JSOI2009]Count

Time Limit: 10 Sec Memory Limit: 64 MB

Description

一个N*M的方格,初始时每个格子有一个整数权值,接下来每次有2个操作:
改变一个格子的权值
求一个子矩阵中某个特定权值出现的个数

Input

每一行有两个数字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的格子数字
(n,m<=300,Q<=5000)
(1<=x<=N,1<=y<=M,1<=c<=100)
(x1<=x<=x2,y1<=y<=y2)

Output

对于每个操作2,按输入中出现的顺序,依次输出一行一个整数表示所求得的个数

Sample Input

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

Sample Output

1
2

题解

直接二维树状数组就可以了。

代码如下

#include<cstdio>
using namespace std;
int Sum[105][305][305],n,m,Q,a[305][305];
void Add(int x,int y,int c,int p){
    for(int i=x;i<=n;i+=i&(-i))
    for(int j=y;j<=m;j+=j&(-j))
    Sum[c][i][j]+=p;
}
int get(int x,int y,int c){
    int Now=0;
    for(int i=x;i;i-=i&(-i))
    for(int j=y;j;j-=j&(-j)) Now+=Sum[c][i][j];
    return Now;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)scanf("%d",&a[i][j]),Add(i,j,a[i][j],1);
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++){
        int opt,x1,y1,x2,y2,c;
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d%d",&x1,&y1,&c);
            Add(x1,y1,a[x1][y1],-1);
            a[x1][y1]=c;
            Add(x1,y1,a[x1][y1],1);
        }else{
            scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&c);
            int Ans=get(x2,y2,c)+get(x1-1,y1-1,c);
            Ans-=get(x1-1,y2,c)+get(x2,y1-1,c);
            printf("%d\n",Ans);
        }
    }
    return 0;
}
posted @ 2018-05-14 13:27  XSamsara  阅读(125)  评论(0编辑  收藏  举报