POJ 2155 Matrix 树状数组

来源:互联网 发布:shuffle python 编辑:程序博客网 时间:2024/05/22 07:50

题目大意:

给定一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 1010int 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;}


原创粉丝点击