zoukankan      html  css  js  c++  java
  • hicocoder1068 区间最值询问(线段树,RMQ-ST算法)

    题目链接:

    http://hihocoder.com/problemset/problem/1068

    我的代码:

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 
     5 using namespace std;
     6 
     7 #define MAXN 1000005
     8 
     9 int w[MAXN];
    10 
    11 struct segNode
    12 {
    13     int left, right, minw;
    14 };
    15 
    16 struct segTree
    17 {
    18     segNode t[4*MAXN];
    19     void build(int i, int l, int r)
    20     {
    21         t[i].left = l;
    22         t[i].right = r;
    23         if(l==r)    t[i].minw = w[l];
    24         else
    25         {
    26             int m = (l+r)/2;
    27             build(2*i, l, m);
    28             build(2*i+1, m+1, r);
    29             t[i].minw = min(t[2*i].minw, t[2*i+1].minw);
    30         }
    31     }
    32     int query(int i, int l, int r)
    33     {
    34         if(t[i].left==l&&t[i].right==r) return t[i].minw;
    35         int m = (t[i].left+t[i].right)/2;
    36         if(r<=m) return query(2*i, l, r);
    37         if(l>m) return query(2*i+1, l, r);
    38         return min(query(2*i, l, m), query(2*i+1, m+1, r));
    39     }
    40 }segtree;
    41 
    42 int main()
    43 {
    44     int n, q;
    45     //while(cin>>n)
    46     while(scanf("%d", &n)!=EOF)
    47     {
    48         for(int i=1; i<=n; ++i)
    49             //cin>>w[i];
    50             scanf("%d", &w[i]);
    51         segtree.build(1, 1, n);
    52         //cin>>q;
    53         scanf("%d", &q);
    54         while(q--)
    55         {
    56             int l, r;
    57             //cin>>l>>r;
    58             scanf("%d%d", &l, &r);
    59             //cout<<segtree.query(1, l, r)<<endl;
    60             printf("%d
    ", segtree.query(1, l, r));
    61         }
    62     }
    63     return 0;
    64 }

    需要注意的是:涉及到频繁的输入输出,最好用C语言的标准输入输出而不要用C++的流式输入输出,否则提交很可能会超时。(我一开始用cin, cout就超时了T^T)。

    这道题目还有一种更简单的实现方法-RMQ-ST算法。它可以在O(nlogn)的时间复杂度进行预处理,以O(1)的复杂度查询。

    f[i][j]表示从i开始长度为2j的区间内的最小值,由于长度为2j的区间可以拆成两个长度为2j-1,于是有:

    f[i][j] = min(f[i][j-1], f[i+2j-1][j-1]);

    这样,对于询问[l, r],设k为不超过区间[l, r]长度的最大2的飞负整数次幂的幂,则询问的结果就是:

    min(f[l][k], f[r-2k+1][k]);

    代码实现如下:

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 #define MAXN 1000005
     7 
     8 int pre_cal[MAXN][21];
     9 
    10 int main()
    11 {
    12     int n, q;
    13     while(scanf("%d", &n)!=EOF)
    14     {
    15         for(int i=1; i<=n; ++i) scanf("%d", &pre_cal[i][0]);
    16         for(int j=1; (1<<j)<=n; ++j)
    17             for(int i=1; i+(1<<(j-1))<=n; ++i)
    18                 pre_cal[i][j] = min(pre_cal[i][j-1], pre_cal[i+(1<<(j-1))][j-1]);
    19         scanf("%d", &q);
    20         while(q--)
    21         {
    22             int l, r;
    23             scanf("%d%d", &l, &r);
    24             int i = 0;
    25             while((1<<i)<=(r-l+1)) ++i;
    26             printf("%d
    ", min(pre_cal[l][i-1], pre_cal[r-(1<<(i-1))+1][i-1]));
    27         }
    28     }
    29     return 0;
    30 }
  • 相关阅读:
    分支(选择)语句练习——7月22日
    语句:分支语句、switch case ——7月22日
    C#语言基础——7月21日
    进制转换——7月20日
    运行Tomcat报错 解决方法
    Mybatis面试题
    java面试题02
    当你没有能力去改变别人命运的时候 就不要随意去伸出援手......
    快速学习MD5的方法
    java面试题01
  • 原文地址:https://www.cnblogs.com/pczhou/p/4297007.html
Copyright © 2011-2022 走看看