题目链接:
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 }