zoukankan      html  css  js  c++  java
  • Hlg 1832 【线段树 && RMQ】.cpp

    题意:

      在给出的区间内求出最大买进卖出的差价。

    思路:

      对于弱数据:维护一个从左到右的最大差价和最小值。即当发现当前值比最小值小的时候更新最小值,否则看一下当前值与之前最小值的差价是否比最大差价大,是就更新最大差价。时间复杂度是O(m*n)

       对于强数据:利用线段树维护一个最大差价、最大值和最小值,查询的时候求出询问的范围内左右子树的最大差价,然后再利用RMQ求出[l, mid]的最小值和[mid+1, r]的最大值,然后返回max(df[rt<<1], df[rt<<1|1], RMQ(mid+1, r)-RMQ(l, mid));这个的时间复杂度是O(nlgn)+m*O(nlgn)

    Tips:

      我的做法是维护了最大值和最小值以便求出最大差值,也可以不维护这个,直接利用RMQ求出最大值和最小值,然后求最大差值。

    Code:

     1 #include <stdio.h>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cmath>
     5 using namespace std;
     6 
     7 const int MAXN = 100010;
     8 int mx[MAXN<<2], mn[MAXN<<2], df[MAXN<<2];
     9 int dpx[MAXN][25], dpn[MAXN][25];
    10 int val[MAXN];
    11 
    12 
    13 void makermq(int n)
    14 {
    15     for (int j = 1; (1<<j) <= n; ++j)
    16         for (int i = 1; i+(1<<j)-1 <= n; ++i) {
    17             dpn[i][j] = min(dpn[i][j-1], dpn[i+(1<<(j-1))][j-1]);
    18             dpx[i][j] = max(dpx[i][j-1], dpx[i+(1<<(j-1))][j-1]);
    19         }
    20 }
    21 
    22 int rmqx(int s, int v)
    23 {
    24     int k = (int)(log((v-s+1)*1.0)/log(2.0));
    25     return max(dpx[s][k], dpx[v-(1<<k)+1][k]);
    26 }
    27 
    28 int rmqn(int s, int v)
    29 {
    30     int k = (int)(log((v-s+1)*1.0)/log(2.0));
    31     return min(dpn[s][k], dpn[v-(1<<k)+1][k]);
    32 }
    33 
    34 void PushUp(int rt)
    35 {
    36     mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
    37     mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);
    38     df[rt] = max(df[rt<<1], df[rt<<1|1]);
    39     df[rt] = max(df[rt], mx[rt<<1|1]-mn[rt<<1]);
    40 }
    41 
    42 void Build(int rt, int l, int r)
    43 {
    44     if (l == r) {
    45         scanf("%d", &mx[rt]);
    46         mn[rt] = mx[rt];
    47         dpn[l][0] = dpx[l][0] = mx[rt];
    48         return;
    49     }
    50     int mid = (l+r)/2;
    51     Build(rt<<1, l, mid);
    52     Build(rt<<1|1, mid+1, r);
    53     PushUp(rt);
    54 }
    55 
    56 int query(int l, int r, int L, int R, int rt)
    57 {
    58     if (L >= l && R <= r) {
    59         return df[rt];
    60     }
    61     int mid = (L+R)/2;
    62     int ans = 0;
    63     if (r <= mid) ans = query(l, r, L, mid, rt<<1);
    64     else if (l > mid) ans = query(l, r, mid+1, R, rt<<1|1);
    65     else {
    66         ans = query(l, r, L, mid, rt<<1);
    67         ans = max(ans, query(l, r, mid+1, R, rt<<1|1));
    68 
    69         ans = max(ans, rmqx(mid+1, r)-rmqn(l, mid));
    70     }
    71     return ans;
    72 }
    73 
    74 int main()
    75 {
    76     //freopen("in.txt", "r", stdin);
    77     int n;
    78     int q, a, b;
    79     while (~scanf("%d", &n)) {
    80         n++;
    81         memset(df, 0, sizeof(df));
    82         memset(mx, 0, sizeof(mx));
    83         memset(mn, 0, sizeof(mn));
    84         Build(1, 1, n);
    85         makermq(n);
    86 
    87         scanf("%d", &q);
    88         while (q--) {
    89             scanf("%d %d", &a, &b);
    90             a++, b++;
    91             printf("%d
    ", query(a, b, 1, n, 1));
    92         }
    93         puts("");
    94     }
    95     return 0;
    96 }
    View Code

    链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1832

    外传野史:这道题其实是某学长的面试题,当时那个学长太紧张了,没想清楚,只想到了可以用线段树维护最大值和最小值来解,但是面试官貌似也不认识线段树,然后提示说这个是股票,最小值必须在最大值的左面,这样单纯的维护最大值最小值就不好使了。

    所以正解的确是用线段树,但是是用线段树维护差值,并用RMQ来帮忙维护 差值 = 右子树指定范围内最大值-左子树指定范围内最小值 的问题。

    这个是zz想到的啦,给他一个good~

  • 相关阅读:
    以用户名注册来分析三种Action获取数据的方式
    Struts2中的OGNL详解 《转》
    Module 'null' not found异常解决办法
    struts标签<logic:iterate>的用法
    struts2的核心和工作原理 <转>
    jstl标签怎么实现分页中下一页
    forward 和redirect
    forward 和redirect的区别
    今天早上起来就想着要问问龙虎有圆通没
    昨天晚上回来弄了两个皮蛋吃
  • 原文地址:https://www.cnblogs.com/Griselda/p/3433671.html
Copyright © 2011-2022 走看看