• POJ 2155 Matrix 树状数组


    一、题目大意

    有一个n*n 全是 0 的矩阵,两种操作

    1、区间反转y1行到y2行,x1列到x2列的所有元素。(反转就是1变0,0变1)

    2、单点查询(x,y)的值

    二、解题思路

    提到反转问题,我们就明白只需要记录操作次数即可,最终操作次数如果是奇数就是1,如果是偶数是0。

    然后我们设 (x,y)坐标位置这个点反转的次数为 S(y,x),我们来考虑下当 [y1,y2]行,[x1,x2]列区间反转对于x和y的影响

    1、当y

    2、当y1<=y<=y2且x1<=x<=x2时,S(y,x)=S(y,x)+1

    3、当 y2

    4、当 y1<=y<=y2 且 x2

    5、当 y2

    我们可以定义一个二维数组bit,然后用bit前y列、前x行的和代表S(y,x)

    针对第一点,不需要进行操作就可以达到

    针对第二点,我们可以将二维bit[y1][x1]+=1,这样当y1<=y且x1<=x时,计算bit前y行和x列的和时就会+1。

    针对第三点,我们需要对x1列以后,y2+1行和之后的行进行处理,所以我们可以对bit[y2+1][x1]+=(-1),这样,计算y2

    针对第四点,我们需要对y1行以后,x2+1列和之后的列进行处理,可以bit[y1][x2+1]+=(-1),这样,计算y1<=y<=y2,x2

    针对第5点,考虑到我们之前对bit[y1][x2+1]和bit[y2+1][x]都做了-1处理,如果计算bit的y2

    然后再简单说下bit如何扩展到二维的情况,举个例子吧,一维树状数组的第4位,保存的是[1,4]的和,第6位保存的是[5,6]的和(这里是因为6=0110,抽出最左边的1转成10进制是2,所以6管理2个元素,也就是它自己和它前面的一个元素)

    如果扩展到二维的情况,那么bit[4][4]就可以管理前4行的[1,4]的和,bit[6][6]就代表着[5,6]区间内的两行的[5,6]区间里元素的值,bit[4][6]代表的是[1,4]区间里行的[5,6]区间里元素的和。bit[6][4]代表的是[5,6]区间里行的[1,4]区间里的元素的和。

    那么树状数组更新第i行第j列的单点值增加x时候,只需要根据 i = i + (i&(-i))来操作所有行,然后针对每一行,设k=j按照 k = k + (k&(-k))依次加x。

    树状数组计算前i行前j列的区间和的时候,只需要根据 i = i - (i&(-i))来计算节点的所有子行,然后针对每一行,设置k=j,按照 k = k - (k&(-k))依次加上所有子元素即可。

    (二维树状数组的话需要创建一个二维数组,然后每次更新和计算下标为i 的 树状数组的下标为k的值)

    (每次求和时,每一行的循环加的元素数量是相同的)

    然后注意下每次一组样例后,多输出一个\n,不然会报 PE

    三、代码

    1. #include
    2. using namespace std;
    3. int bit[1032][1032], n, n_;
    4. void init()
    5. {
    6. n = 1;
    7. while (n < n_)
    8. {
    9. n = n * 2;
    10. }
    11. for (int i = 0; i <= n; i++)
    12. {
    13. for (int j = 0; j <= n; j++)
    14. {
    15. bit[i][j] = 0;
    16. }
    17. }
    18. }
    19. void update(int row, int col, int v)
    20. {
    21. if (row <= 0 || col <= 0)
    22. {
    23. return;
    24. }
    25. for (int i = row; i <= n; i = i + (i & (-i)))
    26. {
    27. for (int j = col; j <= n; j = j + (j & (-j)))
    28. {
    29. bit[i][j] = bit[i][j] + v;
    30. }
    31. }
    32. }
    33. int query(int row, int col)
    34. {
    35. int sum = 0;
    36. for (int i = row; i > 0; i = i - (i & (-i)))
    37. {
    38. for (int j = col; j > 0; j = j - (j & (-j)))
    39. {
    40. sum = sum + bit[i][j];
    41. }
    42. }
    43. return sum;
    44. }
    45. int main()
    46. {
    47. int x, x1, y1, x2, y2, t;
    48. char c;
    49. scanf("%d", &x);
    50. while (x--)
    51. {
    52. scanf("%d%d", &n_, &t);
    53. init();
    54. while (t--)
    55. {
    56. scanf("\n%c", &c);
    57. if (c == 'Q')
    58. {
    59. scanf("%d%d", &x1, &y1);
    60. int result = query(y1, x1);
    61. if (result & 1)
    62. {
    63. printf("1\n");
    64. }
    65. else
    66. {
    67. printf("0\n");
    68. }
    69. }
    70. else if (c == 'C')
    71. {
    72. scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    73. update(y1, x1, 1);
    74. update(y1, x2 + 1, -1);
    75. update(y2 + 1, x1, -1);
    76. update(y2 + 1, x2 + 1, 1);
    77. }
    78. }
    79. printf("\n");
    80. }
    81. return 0;
    82. }

  • 相关阅读:
    Express-01
    Unity中神秘的Transform和transform(小写)的关系
    计算机毕业设计springboot+vue+elementUI校园志愿者管理系统
    实践分享!GitLab CI/CD 快速入门
    经典文献阅读之--Deformable DETR
    [Windows] 植物大战僵尸杂交版
    生成指定位数强Lucas校验伪素数-Arnault1995构造法
    调查:三分之一接受调查的黄金买家认为比特币是更好的选择
    zookeeper客户端命令
    链表相关算法题
  • 原文地址:https://blog.csdn.net/qq_53038151/article/details/133523473