zoukankan      html  css  js  c++  java
  • 【进阶——树状数组】 区间求最值

    上一篇讲的是区间求和,这一篇讲区间求最值。

    首先,a[]数组仍然是保存原始数据。但是c[]数组变了,c[i]将会保存从a[1]a[i]的最值。

    初始化c[]

    当我们输入a[i]时,c[i]需要需要向前依次枚举被c[i]所包含的c[]数组。比如,当i == 8时,需要向前依次枚举c[7], c[6], c[4],取a[8]与这几个c[]中的最值保存在c[8]中。找到c[]的规律了没有?依次是i-1, i-2, i-4...

     1 void Init()
     2 {
     3     int  y;
     4     memset(c, 0, sizeof(c));
     5     for(int i = 1; i <= n; i++)
     6     {
     7         scanf("%d", &y);
     8         a[i] = y;
     9         c[i] = y;
    10         for(int j = 1; j <lowbit(i); j <<= 1)           //需要比较的c[]
    11             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
    12     }
    13 }

    可以看出,每输入一个a[i],处理c[i]的时间复杂度为log2(n),输入n个,初始化的时间复杂度就是n*log2(n)

    修改c[]

    我们改变了一个a[i],那么就需要修改所有与a[i],相关的c[]。修改每个的c[]的方法可以用上面初始化的方法,而需要修改的c[]可以用区间求和里的一段代码确定。

     1 void Maxn(int x, int y)
     2 {
     3     a[x] = y;
     4     for(int i = x; i <= n; i += lowbit(i))              //需要修改的c[]
     5     {
     6         c[i] = y;
     7         for(int j = 1; j < lowbit(i); j <<= 1)          //修改时需要比较的c[]
     8         {
     9             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
    10         }
    11     }
    12 }

    每次修改的时间复杂度近似为log2(n)*log2(n)

    查询:

    查询从a[i]a[j]之间的最值(i <= j)。我们不能直接查看c[j],因为也许c[j]中包含的区间[l, r]l < il > ic[j]不能恰好包含区间[i, j]

    因此,当l < i时,我们就取a[j]与当前已经取到的最值比较,如果a[j]满足取代条件,就用a[j]取代当前最值。

    l >= i,我们取c[j]与当前最值比较,如果c[j],满足取代条件,就用c[j]取代当前最值。

    l == i时,比较结束。

     1 void Query(int l, int r)
     2 {
     3     int ans = 0;
     4     while(1)
     5     {
     6         ans = ans > a[r] ? ans : a[r];
     7         if(r == l) break;
     8         for(r -= 1; r-l >= lowbit(r); r -= lowbit(r))
     9             ans = ans > c[r] ? ans : c[r];
    10     }
    11     printf("%d
    ", ans);
    12 }

    时间复杂度近似为log2(n)

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int N = 200010;
     8 
     9 int a[N], c[N];
    10 int t, n, m;
    11 
    12 int lowbit(int x)
    13 {
    14     return x&(-x);
    15 }
    16 
    17 void Maxn(int x, int y)
    18 {
    19     a[x] = y;
    20     for(int i = x; i <= n; i += lowbit(i))              //需要修改的c[]
    21     {
    22         c[i] = y;
    23         for(int j = 1; j < lowbit(i); j <<= 1)          //修改时需要比较的c[]
    24         {
    25             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
    26         }
    27     }
    28 }
    29 
    30 void Init()
    31 {
    32     int  y;
    33     memset(c, 0, sizeof(c));
    34     for(int i = 1; i <= n; i++)
    35     {
    36         scanf("%d", &y);
    37         a[i] = y;
    38         c[i] = y;
    39         for(int j = 1; j <lowbit(i); j <<= 1)           //需要比较的c[]
    40             c[i] = c[i] > c[i-j] ? c[i] : c[i-j];
    41     }
    42 }
    43 
    44 void Query(int l, int r)
    45 {
    46     int ans = 0;
    47     while(1)
    48     {
    49         ans = ans > a[r] ? ans : a[r];
    50         if(r == l) break;
    51         for(r -= 1; r-l >= lowbit(r); r -= lowbit(r))
    52             ans = ans > c[r] ? ans : c[r];
    53     }
    54     printf("%d
    ", ans);
    55 }
    56 
    57 void Work()
    58 {
    59     char s[2];
    60     int x, y;
    61     for(int i = 1; i <= m; i++)
    62     {
    63         scanf("%s%d%d", s, &x, &y);
    64         if(s[0] == 'U') Maxn(x, y);
    65         else if(s[0] == 'Q') Query(x, y);
    66     }
    67 }
    68 
    69 int main()
    70 {
    71     //freopen("test.in", "r", stdin);
    72     while(~scanf("%d%d", &n, &m))
    73     {
    74         Init();
    75         Work();
    76     }
    77 }
    mod

    树状数组区间求和——
    http://www.cnblogs.com/mypride/p/5001858.html

  • 相关阅读:
    利用Ajax调用controller方法并传递参数
    JS禁用右键+禁用Ctrl+u+禁用F12
    Web端即时通讯、消息推送的实现
    JS禁用微信复制链接、禁用转发
    模拟时钟
    CefSharp 设置cookie
    WinForm使用CefSharp内嵌chrome浏览器
    cefsharp 获取高度
    S 禁止F12和右键操作控制台,兼容各浏览器
    JS判断手机浏览器内核
  • 原文地址:https://www.cnblogs.com/mypride/p/5002556.html
Copyright © 2011-2022 走看看