1452: [JSOI2009]Count 二维树状数组

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1452

题目大意:给一个数字矩阵,两种操作。1.把(x,y)位置的数字改成z,2.查询(x1,y1)(x2,y2)构成的矩阵里头有多少个z

题目解析:

       我们首先考虑一维的情况,L到R有多少个z,为了优化我们开一个二维数组,记录每个z的前缀和,但是对于可修改的在线询问,一个一个的改前缀和是不是很费时,所以用一维树状数组优化。

     好,此时我们已经解决了一维的这个问题。但是这个是二维的,我们怎么搞。

      首先我们把待查询区间分成四块(纸上比划比划)

      1.(1,1)到(x2 , y2);

      2.(1,1)到(x1-1,y1-1);

      3.(1,1)到(x2,y1-1);

      4.(1,1)到(x1-1,y2);

那么(x1,y1)到(x2,y2)的z的个数就是 (手懒直接写上述编号的z的个数)1减3减4加2;

      我们暂且看作我们每行都建立了一个树状数组(修改时间肯定超,总不能一行一行的改吧),这样我们可以暴力每一行,再结合上边说的一维的操作。好我们现在解决超时。

      y坐标方向我们用了树状数组优化,那么行方向可不可以呢,答案是可以的,这样就像两个树状数组重叠一下一样,把这块矩阵分成了很多,就像一维树状数组分成很多一样,切记此处的c[x][y][z],不是(1,1)到(x,y)中有多少个z,而是这个结点的叶子节点之和(往一维那里想)。

     举个例子:

x=y=7     那么单考虑一个一维的树状数组,【1,7】被分为【1,4】【5,6】【7,7】三个区间。

接下来我们考虑二维:

x方向分为【1,4】【5,6】【7,7】y方向同样,所以整个矩阵被分为九块,然后建出了一颗二维的树,我也不会画,因为我只是个小萌新

1452: [JSOI2009]Count 二维树状数组

#include<iostream>
#include<stdio.h>
#include<string.h>
#define lowbit(x) x&(-x)
using namespace std;
int n,m;
int c[305][305][105];
int a[305][305];
int ask(int x,int y,int z){
    int ans=0;
    for(;x;x-=lowbit(x)){
        for(int j=y;j;j-=lowbit(j)){
            ans+=c[x][j][z];
        }
    }
    return ans;
}
void add(int x,int y,int z,int d){
    for(x;x<=n;x+=lowbit(x)){
        for(int j=y;j<=m;j+=lowbit(j)){
            c[x][j][z]+=d;
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(c,0,sizeof(c));
        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);
            }
        }
        int sb,k;scanf("%d",&k);
        while(k--){
            scanf("%d",&sb);
            if(sb==1){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                add(x,y,a[x][y],-1);
                add(x,y,z,1);
                a[x][y]=z;
            }
            else{
                int x1,x2,y1,y2,z;
                scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&z);
                int ans=ask(x2,y2,z)-ask(x1-1,y2,z)-ask(x2,y1-1,z)+ask(x1-1,y1-1,z);
                printf("%d\n",ans);
            }
        }
    }

}