当前位置:   article > 正文

高级数据结构-树状数组总结_高级数据结构的学习与实现 树状数组

高级数据结构的学习与实现 树状数组

高级数据结构-树状数组总结

一维树状数组

1.更改单点,输出区间和
         一般用向上修改,向下统计, 也就是在updata函数里面使用+=,在 sum函数里面使用-=
         完整代码如下

  1. void updata(int x, int num)
  2. {
  3. while (x <= n) //树状数组的大小
  4. {
  5. bit[x] += num;
  6. x += lowbit(x); //lowbit返回2^k 函数内容为return x&-x;
  7. }
  8. }
  1. int sum(int x)
  2. {
  3. int sum = 0;
  4. while (x > 0)
  5. {
  6. sum += bit[x];
  7. x -= lowbit(x);
  8. }
  9. return sum;
  10. }


    例题如下 杭电 敌兵布阵
    题意就是对n个阵地中的某个,进行数目的加减操作,然后输出从a到b阵地的总人数。
    代码如下:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <queue>
  7. #include <cmath>
  8. #include <map>
  9. #include <string>
  10. #include <cstdlib>
  11. using namespace std;
  12. const int MAXN = 50000 + 10;
  13. int BIT[MAXN], t;
  14. int lowbit(int x)
  15. {
  16. return x&-x;
  17. }
  18. void updata(int x, int num)
  19. {
  20. while (x <= t)
  21. {
  22. BIT[x] += num;
  23. x += lowbit(x);
  24. }
  25. }
  26. int sum(int x)
  27. {
  28. int sum = 0;
  29. while (x > 0)
  30. {
  31. sum += BIT[x];
  32. x -= lowbit(x);
  33. }
  34. return sum;
  35. }
  36. int main()
  37. {
  38. #ifdef LOCAL
  39. freopen("in.txt", "r", stdin);
  40. //freopen("out.txt", "w", stdout);
  41. #endif // LOCAL
  42. int T;
  43. int num, a, b;
  44. int Ncase = 1;
  45. scanf("%d", &T);
  46. while (T--)
  47. {
  48. memset(BIT, 0, sizeof(BIT));
  49. scanf("%d", &t);
  50. for (int i = 1; i <= t; ++i)
  51. {
  52. scanf("%d", &num);
  53. updata(i, num); //单点更新
  54. }
  55. printf("Case %d:\n", Ncase++);
  56. char command[10];
  57. while (scanf("%s", command) != EOF)
  58. {
  59. if (command[0] == 'E')
  60. break;
  61. scanf("%d%d", &a, &b);
  62. if (command[0] == 'S')
  63. updata(a, -b); //单点更新
  64. else if (command[0] == 'A')
  65. updata(a, b); //单点更新
  66. else
  67. printf("%d\n", sum(b) - sum(a-1)); //返回总和 因为sum(b) 返回从1到b的值,然后 sum(a-1)返回从1到a-1的值 相减就是a到b的值。
  68. }
  69. }
  70. return 0;
  71. }


2.更改区间,输出单点 

    一般用向下修改,向上统计, 也就是在updata函数里面使用-=,在 sum函数里面使用+=
     完整代码如下

  1. void updata(int x, int num)
  2. {
  3. while (x > 0)
  4. {
  5. bit[x] += num;
  6. x -= lowbit(x); //lowbit返回2^k 函数内容为return x&-x;
  7. }
  8. }

  1. int sum(int x)
  2. {
  3. int sum = 0;
  4. while (x <= n) //树状数组的大小
  5. {
  6. sum += bit[x];
  7. x += lowbit(x);
  8. }
  9. return sum;
  10. }



    例题如下杭电 Color the ball
    题意 在一段连续的区间上 从a到b依次 涂色 也就是值+1 然后输出某个单点的值
    代码如下

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <queue>
  7. #include <cmath>
  8. #include <map>
  9. #include <string>
  10. #include <cstdlib>
  11. using namespace std;
  12. const int MAXN = 100000 + 10;
  13. int bit[MAXN], n;
  14. int lowbit(int x)
  15. {
  16. return x&-x;
  17. }
  18. void updata(int x, int num)
  19. {
  20. while (x > 0)
  21. {
  22. bit[x] += num;
  23. x -= lowbit(x);
  24. }
  25. }
  26. int sum(int x)
  27. {
  28. int sum = 0;
  29. while (x <= n)
  30. {
  31. sum += bit[x];
  32. x += lowbit(x);
  33. }
  34. return sum;
  35. }
  36. int main()
  37. {
  38. #ifdef LOCAL
  39. freopen("in.txt", "r", stdin);
  40. //freopen("out.txt", "w", stdout);
  41. #endif // LOCAL
  42. int a, b;
  43. while (scanf("%d", &n) != EOF && n != 0)
  44. {
  45. memset(bit, 0 ,sizeof(bit));
  46. for (int i = 1; i <= n; ++i)
  47. {
  48. scanf("%d%d", &a, &b);
  49. updata(b, 1); //单点更新
  50. updata(a - 1, -1); //单点更新
  51. }
  52. printf("%d", sum(1)); //因为单点更新的时候取+1, -1 相互抵消,所以sum(1)就是单点的值
  53. for (int i = 2; i <= n; ++i)
  54. printf(" %d", sum(i));
  55. printf("\n");
  56. }
  57. return 0;
  58. }


    一维树状数组更新和求和可以在数轴上进行模拟,用区间来表示。理解更快。

二维树状数组

    二维树状数组在操作是,是以二维的直角坐标系为基准,在更新时应该注意边界问题

    1.单点更新,输出区间

     在updata里面使用 += 在Query里面使用-=

    实例如下

   

  1. void updata(int x, int y, int num)
  2. {
  3. int temp = x;
  4. while (y <= n)
  5. {
  6. x = temp;
  7. while (x <= n)
  8. {
  9. bit[x][y] += num;
  10. x += lowbit(x);
  11. }
  12. y += lowbit(y);
  13. }
  14. }
  1. int Query(int x, int y)
  2. {
  3. int sum = 0;
  4. int temp = x;
  5. while (y > 0)
  6. {
  7. x = temp; //指针一定要初始化
  8. while (x > 0)
  9. {
  10. sum += bit[x][y];
  11. x -= lowbit(x);
  12. }
  13. y -= lowbit(y);
  14. }
  15. return sum;
  16. }
    例题 POJ Mobile phones
   题意 在一个已知的二维空间,输入命令1  表示 在 所指示的点加上指定的 数  输入命令2 则输出所指向的二维区间的和
    用向上更新,向下求和

    代码如下
   
   
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <queue>
  7. #include <cmath>
  8. #include <map>
  9. #include <string>
  10. #include <list>
  11. #include <vector>
  12. #include <cstdlib>
  13. using namespace std;
  14. const int MAXN = 1250;
  15. int bit[MAXN][MAXN], n;
  16. int lowbit(int x)
  17. {
  18. return x&-x;
  19. }
  20. void updata(int x, int y, int num)
  21. {
  22. int temp = x;
  23. while (y <= n)
  24. {
  25. x = temp;
  26. while (x <= n)
  27. {
  28. bit[x][y] += num;
  29. x += lowbit(x);
  30. }
  31. y += lowbit(y);
  32. }
  33. }
  34. int Query(int x, int y)
  35. {
  36. int sum = 0;
  37. int temp = x;
  38. while (y > 0)
  39. {
  40. x = temp;
  41. while (x > 0)
  42. {
  43. sum += bit[x][y];
  44. x -= lowbit(x);
  45. }
  46. y -= lowbit(y);
  47. }
  48. return sum;
  49. }
  50. int main()
  51. {
  52. #ifdef LOCAL
  53. freopen("in.txt", "r", stdin);
  54. //freopen("out.txt", "w", stdout);
  55. #endif // LOCAL
  56. int com;
  57. int x, y, a, b;
  58. while (scanf("%d", &com) != EOF && com != 3)
  59. {
  60. if (com == 0)
  61. {
  62. scanf("%d", &n);
  63. memset(bit, 0, sizeof(bit));
  64. }
  65. else if (com == 1)
  66. {
  67. scanf("%d%d%d", &x, &y, &a);
  68. updata(x + 1, y + 1, a); //单点向上更新
  69. }
  70. else
  71. {
  72. scanf("%d%d%d%d", &x, &y, &a, &b);
  73. x++; y++; a++; b++;
  74. printf("%d\n", Query(a, b) - Query(a, y - 1) - Query(x - 1, b) + Query(x - 1, y - 1)); //向下求和 求和注意筛选区间以及边界问题
  75. }
  76. }
  77. return 0;
  78. }

关于区间的筛选和边界  如图所示



2.区间更新,输出单点
    
和一维的类似 在二维里面,仍然是用两个坐标之间的差值,代表所更新的区间,而坐标之间的差值,需要考虑,上图所示
   例子代码,就不写了,和一维类似,只是改变单点更新里面的大小。
    直接上例题:  POJ Matrix
   题意: 给定大小的矩阵中,C表示更新区段,Q表示,输入单点值  这里只有0和1 两种 所以采用累加 然后求和
    代码如下:
   
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <queue>
  7. #include <cmath>
  8. #include <map>
  9. #include <string>
  10. #include <cstdlib>
  11. using namespace std;
  12. const int MAXN = 1010;
  13. int bit[MAXN][MAXN], n;
  14. int lowbit(int x)
  15. {
  16. return x&-x;
  17. }
  18. void updata(int x, int y, int num)
  19. {
  20. int temp = x;
  21. while (y <= n)
  22. {
  23. x = temp;
  24. while (x <= n)
  25. {
  26. bit[x][y] += num;
  27. x += lowbit(x);
  28. }
  29. y += lowbit(y);
  30. }
  31. }
  32. int Query(int x, int y)
  33. {
  34. int sum = 0;
  35. int temp = x;
  36. while ( y > 0)
  37. {
  38. x = temp;
  39. while( x > 0)
  40. {
  41. sum += bit[x][y];
  42. x -= lowbit(x);
  43. }
  44. y -= lowbit(y);
  45. }
  46. return sum;
  47. }
  48. int main()
  49. {
  50. #ifdef LOCAL
  51. freopen("in.txt", "r", stdin);
  52. //freopen("out.txt", "w", stdout);
  53. #endif // LOCAL
  54. int t, T;
  55. int blank = 0;
  56. int x1, x2, y1, y2;
  57. scanf("%d", &T);
  58. while (T--)
  59. {
  60. memset(bit, 0, sizeof(bit));
  61. scanf("%d%d", &n, &t);
  62. if (blank++ != 0)
  63. printf("\n");
  64. while (t--)
  65. {
  66. char command[3];
  67. scanf("%s", command);
  68. if (command[0] == 'C')
  69. {
  70. scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
  71. updata(x1, y1, 1);
  72. updata(x2 + 1, y1, -1);
  73. updata(x1, y2 + 1, -1);
  74. updata(x2 + 1, y2 + 1, 1); //更新时 区间的选用 参照上面的图片
  75. }
  76. else
  77. {
  78. scanf("%d%d", &x1, &y1);
  79. printf("%d\n", Query(x1, y1) % 2);
  80. }
  81. }
  82. }
  83. return 0;
  84. }


小结:  树状数组在应用时,关键在于,确定更新方式,以及更新区间



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/654175
推荐阅读
相关标签
  

闽ICP备14008679号