当前位置:   article > 正文

树状数组求区间最大值(转载)

树状数组求区间最大值

[数组的含义]

1、在维护和查询区间和的算法中,h[x]中储存的是[x,x-lowbit(x)+1]中每个数的和 .

2、在求区间最值的算法中,h[x]储存的是[x,x-lowbit(x)+1]中每个数的最大值。

求区间最值的算法中还有一个a[i]数组,表示第i个数是多少,也就是原数组。

[单点修改后的更新]

1、在维护区间和的算法中,是这样维护单点修改的

  1. void update(int i,int v){
  2. //区间和更新
  3. while(i<=n){
  4. h[i]+=v;
  5. i+=lowbit(i) ;
  6. }
  7. }

2、在来看维护区间最大值的算法,我们先看一整段区间[1,n]都需要初始化的情况。(即 h[] 数组都为0,现在需要用 a[] 数组更新 h[] 数组)

  1. void updata(int i, int val)
  2. {
  3. while (i <= n)
  4. {
  5. h[i] = max(h[i], val);
  6. i += lowbit(i);
  7. }
  8. }

可以发现:对于x,可以转移到x的只有,x-2^{0} ,x-2^{1},x-2^{2} ... . .x-2^{k}(k满足2^k < lowbit(x)且2^(k+1)>=lowbit(x))

举例:

若 x = 1010000

= 1001000 + lowbit(1001000) = 1001000 + 1000 = 1001000 + 2^3

= 1001100 + lowbit(1001100) = 1001100 + 100 = 1001100 + 2^2

= 1001110 + lowbit(1001110) = 1001110 + 10 = 1001110 + 2^1

= 1001111 + lowbit(1001111) = 1001111 + 1 = 1001111 + 2^0

所以对于每一个h[i],在保证h[1...i-1]都正确的前提下,要重新计算h[i]值的时间复杂度是O(logn),具体方法如下:

  1. h[x] = a[x];
  2. lx = lowbit(x);
  3. for (i=1; i<lx; i<<=1)
  4. h[x] = max(h[x], h[x-i]);
  5. x += lowbit(x);

这样,我们就可以得到一个和树状数组维护区间合算法很像的算法

  1. void updata(int x)
  2. {
  3. int lx, i;
  4. while (x <= n)
  5. {
  6. h[x] = a[x];
  7. lx = lowbit(x);
  8. for (i=1; i<lx; i<<=1)
  9. h[x] = max(h[x], h[x-i]);
  10. x += lowbit(x);
  11. }
  12. }

这个算法的时间复杂度是O((logn)^2),所以现在就可以在O((logn)^2)的时间内完成最值的区间维护了。

[区间查询]

1、树状数组求区间合的算法是这样子的:

  1. int query(int i)
  2. {
  3. int ans = 0;
  4. while (i > 0)
  5. {
  6. ans += h[i];
  7. i -= lowbit(i);
  8. }
  9. return ans;
  10. }

2、树状数组求区间最大值:

直接照搬求区间合的方法显然是不行的。

因为区间合中,要查询[x,y]的区间合,是求出[1,x-1]的合与[1,y]的合,然后相减就得出了[x,y]区间的合。

而区间最值是没有这个性质的,所以只能够换一个思路。

设query(x,y),表示[x,y]区间的最大值

因为h[y]表示的是[y,y-lowbit(y)+1]的最大值。

所以,可以这样求解:

若y-lowbit(y) > x ,则query(x,y) = max( h[y] , query(x, y-lowbit(y)) );

若y-lowbit(y) <=x,则query(x,y) = max( a[y] , query(x, y-1);

这个递归求解是可以求出解的,且可以证明这样求解的时间复杂度是O((logn)^2)

  1. int query(int x, int y)
  2. {
  3. int ans = 0;
  4. while (y >= x)
  5. {
  6. ans = max(a[y], ans);
  7. y --;
  8. for (; y-lowbit(y) >= x; y -= lowbit(y))
  9. ans = max(h[y], ans);
  10. }
  11. return ans;
  12. }

时间复杂度的证明:(换成二进制来看)

因为y经过Logn次变换以后,其与x不同的最高位至少下降了1位,所以最多进行(logn)^2次变换

举例:

y = 1010000

x = 1000001

1010000

=> 1001111 => 1001110 =>1001100 =>1001000

=>1000111 => 1000110 => 1000100

=> 1000011 = > 1000010

=>1000001

=>1000000 < 1000001
 

模板题: I Hate It HDU - 1754

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cmath>
  5. #include <set>
  6. #include <cstring>
  7. #include <stack>
  8. #include <vector>
  9. #include <queue>
  10. #define Swap(a,b) a ^= b ^= a ^= b
  11. #define cl(a,b) memset(a,b,sizeof(a))
  12. using namespace std ;
  13. typedef long long LL;
  14. LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
  15. LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
  16. const int MAX = 3e5;
  17. const int inf = 0xffffff;
  18. const LL mod = 1e9+7 ;
  19. int minn = 0x3f3f3f3f ;
  20. int maxx = -0x3f3f3f3f;
  21. // ----+-+------------------------
  22. int n ;
  23. int a[MAX] ;
  24. int c[MAX] ;
  25. int lowbit(int x){return x&(-x);}
  26. void update(int i,int v){
  27. //区间和更新
  28. while(i<=n){
  29. c[i]+=v;
  30. i+=lowbit(i) ;
  31. }
  32. }
  33. void Update(int x){
  34. //区间最值更新
  35. int lx ,i ;
  36. while(x<=n){
  37. c[x] = a[x];
  38. lx = lowbit(x) ;
  39. for(i = 1 ;i<lx;i<<=1){
  40. c[x] = max(c[x],c[x-i]);
  41. }
  42. x+=lowbit(x);
  43. }
  44. }
  45. int query(int x ,int y){
  46. // 区间最大
  47. int ans = 0 ;
  48. while(y>=x){
  49. ans = max(a[y],ans) ;
  50. y-- ;
  51. for(; y - lowbit(y)>=x ;y-=lowbit(y)){
  52. ans = max(c[y],ans) ;
  53. }
  54. }
  55. return ans ;
  56. }
  57. int sum(int i){
  58. //区间和
  59. int ans = 0 ;
  60. while(i){
  61. ans+=c[i] ;
  62. i-=lowbit(i) ;
  63. }
  64. return ans ;
  65. }
  66. int main()
  67. {
  68. ios_base::sync_with_stdio(false);
  69. cin.tie(NULL),cout.tie(NULL);
  70. int m ;
  71. while(scanf("%d%d",&n,&m)!=EOF){
  72. for(int i = 1 ;i<=n;i++){
  73. c[i] = 0 ;
  74. }
  75. for(int i = 1; i<=n ;i++){
  76. scanf("%d",&a[i]);
  77. Update(i) ;
  78. }
  79. // ---------------------------
  80. while(m--){
  81. char op[5] ;
  82. int x ,y ;
  83. int ans ;
  84. scanf("%s",op);
  85. if(op[0]=='Q'){ // 查询
  86. scanf("%d%d",&x,&y);
  87. ans = query(x,y) ;
  88. printf("%d\n",ans);
  89. }
  90. else{
  91. scanf("%d%d",&x,&y);
  92. a[x] = y ;
  93. Update(x);
  94. }
  95. }
  96. }
  97. return 0;
  98. }

 

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

闽ICP备14008679号