POJ 1195 Mobile phones(树状数组)

在一个初始矩阵map中进行操作 初始值为0

4种操作

输入0 后面跟着n为矩阵的size 为n*n

输入1 后面跟着 x y v 意思就是在 (x,y)位置的数增加 v

输入2 后面跟着 x1 y1 x2 y2 意思就是查询(x1 ,y1 )到(x2,y2)中的数的和

输入3 程序停止

update操作很简单  就是运用二维树状数组在(x,y)增加v就可以了 如果v<0也一样就是减

getsum求和操作也差不多  想一下在四边形(x1,y1 )到(x2,y2)中求和其实就是

(1,1)到(x2,y2)的总和 - (1,1)到(x1-1,y2)的总和 - (1,1)到(x2,y1-1)的总和再 + (1,1)到(x1,y1)的和

          因为(x1,y1)在  (1,1)到(x1-1,y2)的总和 - (1,1)到(x2,y1-1)的总和  中被减了两次

          自己画画图应该就可以理解了

  至于坐标的++是因为如果坐标为0的话 low(0)会死循环 其实坐标全部++的话结果是一样的
写的时候吧memset函数放在了while里面.....然后自己很无语了查了一下

       上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1102;
int map[N][N];
int n;
int low(int i)
{
    return i&(-i);
}
void update(int x,int y,int v)
{
    //printf("n= %d",n);
    for(int i=x; i<=n; i+=low(i))
        for(int j=y; j<=n; j+=low(j))
        {
           // printf("x=%d y=%d v=%d\n",x,y,v);
            map[i][j]+=v;
           // printf("v= %d ",v);
        }
}
int getsum(int x,int y)
{
    int sum=0;
    for(int i=x; i>0; i-=low(i))
        for(int j=y; j>0; j-=low(j))
            sum+=map[i][j];
    return sum;
}
int main()
{
    int m,x,y,x1,y1,x2,y2;
    int a;
    int num;
    scanf("%d%d",&m,&n);

    // printf("m== %d n== %d",m,n);
    memset(map,0,sizeof(map));
    n++;
    //printf("n= %d",n);
    while(cin>>num&&num!=3)
    {
        if(num==1)
        {
            // printf("num==1\n");
            scanf("%d%d%d",&x,&y,&a);
            x++;
            y++;
            //printf("x=%d y=%d a=%d\n",x,y,a);
            update(x,y,a);

        }
        if(num==2)
        {
            //  printf("num==2\n");
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x1++;
            y1++;
            x2++;
            y2++;
            int ans=getsum(x2,y2)-getsum(x1-1,y2)-getsum(x2,y1-1)+getsum(x1-1,y1-1);
            printf("%d\n",ans);
        }


    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dioml/article/details/50719432