二维树状数组-POJ 2155 Matrix

梦里梦外; 2023-05-22 14:25 161阅读 0赞

文章目录

  • 树状数组
  • 例题
    • 题意
    • 分析
    • 代码
  • 小结

树状数组


  • 什么是树状数组?
    简单来说,就是暴力遍历数组来解决区间问题等,不过遍历的路径使用了位运算来进行压缩,复杂度是O(log2(n))这样就不会超时了(为所欲为?)。
  • lowbit()操作
    其核心是神奇的lowbit操作,lowbit(x)=x&(-x),它的功能是找到x的二进制数的最后一个1,原理是利用负数的补码表示,补码是原码取反加一。例如x=6=00000110(2),-x=x补=11111010(2),那么lowbit(x)=x&(-x)=10(2)=2。
    从lowbit()引出数组a[],a[x]的值是把ax(题目输入初始值)和他前面的m个数相加,如下表所示:
    在这里插入图片描述
    图形化:
    在这里插入图片描述
    那么通过数组a[],就可以求sum,例如sum(8)=a[8],sum(7)=a[7]+a[6]+a[4],sum(6)=a[6]+a[4],如此一来不就是我们要的路径压缩了吗?
    同样地,更新ax时也要更新a[],例如更新a3,那么首先更改a[3];然后3+lowbit(3)=4,更改a[4];接着4+lowbit(4)=8,更改a[8]。
  • 二维树状数组
    相应的,我们可以推导出二维树状数组,例如更新点求区间输入坐标(x,y),(u,v)求sum黄色区域,如下图所示:
    在这里插入图片描述
    由图易得所求区间黄色区域为sum(u,v)-sum(x-1,v)-sum(u,y-1)+sum(x-1,y-1)

例题


POJ-2155

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.

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变1,1变0),然后多次询问某个点是0还是1。

分析

更新区间求点,用二维树状数组解决,每次更新子矩阵+1,最后求点%2就得到结果。(其实就是二维数组模拟的思路,压缩路径罢了)。

代码

  1. #include<cstdio>
  2. #include<string.h>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn = 1003;
  6. char s[5];
  7. int a[maxn][maxn], n;
  8. int lowbit(int x) {
  9. return (x & (-x));
  10. }
  11. void update(int x, int y) {
  12. for (int i = x; i <= n; i += lowbit(i)) {
  13. for (int j = y; j <= n; j += lowbit(j)) {
  14. a[i][j]++;
  15. }
  16. }
  17. }
  18. int sum(int x, int y) {
  19. int res = 0;
  20. for (int i = x; i > 0; i -= lowbit(i)) {
  21. for (int j = y; j > 0; j -= lowbit(j))
  22. res += a[i][j];
  23. }
  24. return res;
  25. }
  26. int main() {
  27. int ca, t;
  28. int x, y, u, v;
  29. scanf("%d", &ca);
  30. while (ca--) {
  31. memset(a, 0, sizeof(a));
  32. scanf("%d%d", &n, &t);
  33. while (t--) {
  34. scanf("%s%d%d", s, &x, &y);
  35. if (s[0] == 'C') {
  36. scanf("%d%d", &u, &v);
  37. x++, y++;
  38. u++, v++;
  39. update(u, v);
  40. update(x - 1, y - 1);
  41. update(x - 1, v);
  42. update(u, y - 1);
  43. }
  44. else {
  45. printf("%d\n", sum(x, y) % 2);
  46. }
  47. }
  48. printf("\n");
  49. }
  50. return 0;
  51. }

小结


  1. 树状数组能解决的题都能用线段树解决,但是树状数组编程复杂度低,完成效率更高!(大佬请无视)

原创不易,请勿转载(本不富裕的访问量雪上加霜 )
博主首页:https://blog.csdn.net/qq_45034708
如果文章对你有帮助,记得关注点赞收藏❤

发表评论

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

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

相关阅读