POJ 2155 Matrix(二维树状数组+数组数组区间更新+单点查询)

柔光的暖阳◎ 2022-06-11 00:26 271阅读 0赞

Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N).

We can change the matrix in the following way. Given a rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2), we change all the elements in the rectangle by using “not” operation (if it is a ‘0’ then change it into ‘1’ otherwise change it into ‘0’). To maintain the information of the matrix, you are asked to write a program to receive and execute two kinds of instructions.

  1. C x1 y1 x2 y2 (1 <= x1 <= x2 <= n, 1 <= y1 <= y2 <= n) changes the matrix by using the rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2).
  2. Q x y (1 <= x, y <= n) querys A[x, y].

Input

The first line of the input is an integer X (X <= 10) representing the number of test cases. The following X blocks each represents a test case.

The first line of each block contains two numbers N and T (2 <= N <= 1000, 1 <= T <= 50000) representing the size of the matrix and the number of the instructions. The following T lines each represents an instruction having the format “Q x y” or “C x1 y1 x2 y2”, which has been described above.

Output

For each querying output one line, which has an integer representing A[x, y].

There is a blank line between every two continuous test cases.

Sample Input

  1. 1
  2. 2 10
  3. C 2 1 2 2
  4. Q 2 2
  5. C 2 1 2 1
  6. Q 1 1
  7. C 1 1 2 1
  8. C 1 2 1 2
  9. C 1 1 2 2
  10. Q 1 1
  11. C 1 1 2 1
  12. Q 2 1

Sample Output

  1. 1
  2. 0
  3. 0
  4. 1

题解:

题目意思就是给一个大小为n*n的二维矩阵,一开始全部是0,然后操作数是t,如果输出字符为”Q”就是询问矩阵x,y位置的值,为”C”,然后输出两个点坐标,表示矩阵的左上角和右下角坐标,在这些矩阵里面的值取反。。不知道用线段树怎么做,后来看一篇二维树状数组的博客看懂了。

首先写出这题你要会树状数组的区间更新,没错树状数组也可以区间更新,原理不太清楚qaq我就先讲一下做法,就是假如要在一个区间x,y上加上一个值v,那么就在数组sum[x]处加上v,在sum[y+1]处减去v,区间更新就完成了,不同的是当查询单点处x的情况的时候,单点的值是sum[1]+…+sum[x],累加起来就是单点处的值了。

如何说说我的理解:

在sum[x]处加上v,因为更新是往后更新的(每次加上x&(-x)),所以这时后面的区间每个都多了个v,然后再sum[y+1]处减去v,就相当于把区间外多加上的v去掉,这就完成了[x,y]内加上v,因为这里的区间更新比较特殊,所以查询的时候每一点的值要把前面的区间值全部加上。。。感觉我说了我自己都不太懂,就这样吧

然后因为讲解这题要画图感受,所以我就直接贴我看过的博客好了点击打开链接

这个博客的图对这题的理解很有帮助,二维中,假如图是n*n的,如果在[x,y]处加了v就相当于以左上角坐标[x,y],到右下角坐标[n*n]的大矩形里面全部值加上了v,然后后续操作就是修剪加多了的地方,加上剪多了的地方最后就完成了更新

代码:

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<map>
  4. #include<algorithm>
  5. #include<math.h>
  6. #include<queue>
  7. #include<stack>
  8. #include<string>
  9. #include<cstring>
  10. using namespace std;
  11. int sum[1005][1005];
  12. int n;
  13. int lowbit(int x)
  14. {
  15. return x&(-x);
  16. }
  17. int getsum(int x,int y)
  18. {
  19. int s=0;
  20. while(x>0)
  21. {
  22. int t=y;
  23. while(t>0)//二维需要理解
  24. {
  25. s+=sum[x][t];
  26. t-=lowbit(t);
  27. }
  28. x-=lowbit(x);
  29. }
  30. return s%2;//精髓
  31. }
  32. void update(int x,int y,int v)
  33. {
  34. while(x<=n)//与查询差不多
  35. {
  36. int t=y;
  37. while(t<=n)
  38. {
  39. sum[x][t]+=v;
  40. t+=lowbit(t);
  41. }
  42. x+=lowbit(x);
  43. }
  44. }
  45. int main()
  46. {
  47. int i,j,test,m,x1,y1,x2,y2,x,y;
  48. char c;
  49. scanf("%d",&test);
  50. while(test--)
  51. {
  52. memset(sum,0,sizeof(sum));//要初始化
  53. scanf("%d%d",&n,&m);
  54. for(i=0;i<m;i++)
  55. {
  56. getchar();//吸收回车
  57. scanf("%c",&c);
  58. if(c=='C')
  59. {
  60. scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
  61. update(x1,y1,1);//往大矩形里加上了1
  62. update(x2+1,y1,-1);
  63. update(x1,y2+1,-1);//修剪这个大矩形
  64. update(x2+1,y2+1,1);//加上多剪了的
  65. }
  66. else
  67. {
  68. scanf("%d%d",&x,&y);
  69. printf("%d\n",getsum(x,y));
  70. }
  71. }
  72. if(test)
  73. printf("\n");
  74. }
  75. return 0;
  76. }

发表评论

表情:
评论列表 (有 0 条评论,271人围观)

还没有评论,来说两句吧...

相关阅读