关闭

POJ 2155 Matrix 树状数组

标签: 树状数组 二维 poj
349人阅读 评论(0) 收藏 举报
分类:

题目大意:

给定一N*N的矩阵,每个元素为1或0,初始全为0,有如下两种操作

(1)将某一个矩形区域内的所有元素取反,即1改为0,0改为1

(2)询问某一个元素的值,输出0或1

首先不难看出,因为只有01所以与其取反,不如给区间中的某个元素都+1,和开关灯问题的性质相同,最后模2即可;

查询某个点的当前的值,可以转化为查询当前所有的操作中有多少个操作区间包含所查询点(因为每个操作都是给区间中的每个元素+1嘛);

一个区间可以用对角线上的两个顶点表示,如果一个点在这个区间中,那么从矩阵(0,0)位置到该点做组成的矩阵一定包含且只包含一个顶点;

但是这样的话无法区分矩阵外面的点,如果用四个顶点表示这个矩阵呢?这时,矩阵内点所围的矩阵包含一个顶点,而矩阵外的点所围的矩阵包含0、2或4个顶点,模2恰好为0,这样就能通过从(0,0)到某点矩阵所包含的顶点数来完成矩阵内外点的区分了

再由叠加的性质,通过计算顶点数的和可以在模2的意义下区分查询点点被多少个矩阵所围

于是问题就转化为了:以(0,0)和所询问点(x,y)所围成的矩形中包含多少顶点,即子矩阵矩阵元素和是多少?每插入一个矩形,就将其四个顶点插入树状数组,查询时,即求给定区间内的元素和,解决~


关于树状数组:

树状数组是什么?树状数组虽然描述起来是数组,但是表示其元素的关系上应该用类似树的形式画出

树状数组能做什么?最常用的目的:求某个区间的和,给定一个数组若求一段区间的和,我们可以通过预处理出每个“前缀”的和在查询时得到O(1)的复杂度,然而如果这个数组是动态的话,比如我们可以修改某个元素的值,再查询时如果不做预处理,修改O(1),查询需要整体求和O(n);如果预处理,查询O(n),修改需要修改所有包含这个元素的值O(n)。而树状数组就是在这两种状况的一个平衡,它所做的是“不完全”的预处理,将修改的一部分代价转移到查寻时来做,这样查寻和修改都是O(logn),效率较高

而树状数组扩展到高维也很容易,它不过是一个求和的预处理而已

顺便越发的觉得树状数组这个结构十分优美了,虽然所能做的比较有限,但是实现起来相当简单


下面是这道题的代码,注释不多,希望上面的文字描述大概就够了....

#include <cstdio>
#include <cstring>
#define MAXN 1010

int c[MAXN][MAXN];

int lowbit(int k)
{
    return k & -k;
}
void modify(int a, int b, int d)
{
    for (int i = a; i < MAXN; i += lowbit(i))
    {
        for (int j = b; j < MAXN; j += lowbit(j))
        {
            c[i][j] += d;
        }
    }
}
int check(int a, int b)
{
    int total = 0;
    for (int i = a; i > 0; i -= lowbit(i))
    {
        for (int j = b; j > 0; j -= lowbit(j))
        {
            total += c[i][j];
        }
    }
    return total;
}


int main()
{
    int caseSet, n , t;
    char str[3];
    int x1, y1, x2, y2;
    int tmp;
    scanf("%d", &caseSet);
    while (caseSet--)
    {
        scanf("%d %d", &n, &t);
        memset(c, 0, sizeof(c));

        while (t--)
        {
            scanf("%s", str);

            switch (str[0])
            {
            case 'C':
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                x2++; y2++; // 这里注意顶点的设置应类似“左闭右开”的形式,否则查询边上的点的时候可能会出问题
                modify(x2, y2, 1);
                modify(x1, y2, 1);
                modify(x2, y1, 1);
                modify(x1, y1, 1);
                break;
            case 'Q':
                scanf("%d%d", &x1, &y1);
                tmp = check(x1, y1);
                printf("%d\n", tmp % 2);
                break;
            }

        }
        printf("\n");
    }
    return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4580次
    • 积分:130
    • 等级:
    • 排名:千里之外
    • 原创:9篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    最新评论