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\n", 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\n", min(pre_cal[l][i-1], pre_cal[r-(1<<(i-1))+1][i-1]));
27         }
28     }
29     return 0;
30 }

 

posted @ 2015-02-21 14:55  __brthls  阅读(123)  评论(0)    收藏  举报