SDUTOJ 3312

题目描述
给出一个n*n的矩阵,矩阵中只有0和1,现在有两种操作:
1 x y 将第x行第y列的数字改变(0变1,1变0)
2 x1 y1 x2 y2求由左上角(x1,y1)到右下角(x2,y2)组成的矩形中的1的个数。
现在初始的矩阵全是0,之后有一系列操作。保证数据输入合法。
输入
第一行输入一个正整数T,代表测试组数。(T <= 10)
每组测试数据的第一行有两个数n,m。(1 <= n <= 500 , 1 <= m <= 10000)
之后是连续m行,代表m次操作。(1 <= x1,y1 <= x2,y2 <= n)
输出
对每次询问输出(x1,y1)到(x2,y2)矩形内的1的个数
示例输入

1
3 3
1 2 2
1 1 1
2 1 1 3 3

示例输出

2
标准的二维树状数组

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>

using namespace std;
 int n,m;
int a[550][550];
int Map[550][550];
int lowbit(int x)
{
    return x&(-x);
}

void update(int x,int y,int d)
{
    int i=x,j;
    while(i<=n)
    {
        j=y;
        while(j<=n)
        {
            a[i][j]+=d;
            j+=lowbit(j);
        }
        i+=lowbit(i);
    }
}
int Query(int x,int y)
{
    int sum=0;
    int i=x,j;
    while(i>0)
    {
        j=y;
        while(j>0)
        {
            sum+=a[i][j];
            j-=lowbit(j);
        }
        i-=lowbit(i);
    }
    return sum;
}

int main()
{
    int T;
    int flag;
    int x1,y1,x2,y2,d;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        memset(Map,0,sizeof(Map));
        memset(a,0,sizeof(a));
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&flag);
            if(flag==1)
            {
                scanf("%d %d",&x1,&y1);
                if(Map[x1][y1]==1)
                {
                    Map[x1][y1]=0;
                    d=-1;
                }
                else
                {
                    Map[x1][y1]=1;
                    d=1;
                }
                update(x1,y1,d);
            }
            else
            {
                scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
                printf("%d
",Query(x2,y2)-Query(x1-1,y2)-Query(x2,y1-1)+Query(x1-1,y1-1));
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/juechen/p/5255926.html