PKU3624 ST算法
RMQ问题
题目大意:给出一个数列,在给出一系列询问,(a,b)查询a到b之间最大值-最小值。
解法一:线段树
1
/*
2 * Problem: USACO 2007 January Silver- lineupg PKU 3264
3 * Author: Xu Fei
4 * Time: 2010.8.13 16:21
5 * Method: 线段树
6 */
7 #include < iostream >
8 #include < cstdio >
9 using namespace std;
10
11 const int MaxN = 50001 ,INF = 0xFFFFFFF ;
12
13 struct Node
14 {
15 int a,b,ma,mi;
16 }tree[MaxN * 4 ];
17 int N,Q;
18 int A[MaxN];
19 int Max,Min;
20
21 inline int max( int a, int b) { return a > b ? a:b; }
22 inline int min( int a, int b) { return a < b ? a:b; }
23
24 void build( int num, int l, int r)
25 {
26 tree[num].a = l;
27 tree[num].b = r;
28 tree[num].ma =- INF;
29 tree[num].mi = INF;
30 if (l < r)
31 {
32 int mid = (l + r) >> 1 ;
33 build(num << 1 ,l,mid);
34 build((num << 1 ) + 1 ,mid + 1 ,r);
35 tree[num].ma = max(tree[num << 1 ].ma,tree[(num << 1 ) + 1 ].ma);
36 tree[num].mi = min(tree[num << 1 ].mi,tree[(num << 1 ) + 1 ].mi);
37 }
38 else
39 {
40 tree[num].ma = A[l];
41 tree[num].mi = A[l];
42 }
43 }
44 void query( int num, int l, int r)
45 {
46 if (tree[num].a == l && tree[num].b == r)
47 {
48 Max = max(Max,tree[num].ma);
49 Min = min(Min,tree[num].mi);
50 return ;
51 }
52 int mid = (tree[num].a + tree[num].b) >> 1 ;
53 if (r <= mid)
54 query(num << 1 ,l,r);
55 else if (l > mid)
56 query((num << 1 ) + 1 ,l,r);
57 else
58 {
59 query(num << 1 ,l,mid);
60 query((num << 1 ) + 1 ,mid + 1 ,r);
61 }
62 }
63 int main()
64 {
65 freopen( " lineupg.in " , " r " ,stdin);
66 freopen( " lineupg.out " , " w " ,stdout);
67 int i,a,b;
68 scanf( " %d%d " , & N, & Q);
69 for (i = 1 ;i <= N; ++ i)
70 scanf( " %d " ,A + i);
71 build( 1 , 1 ,N);
72 for (i = 1 ;i <= Q; ++ i)
73 {
74 scanf( " %d%d " , & a, & b);
75 Max =- INF; Min = INF;
76 query( 1 ,a,b);
77 printf( " %d\n " ,Max - Min);
78 }
79 return 0 ;
80 }
81
2 * Problem: USACO 2007 January Silver- lineupg PKU 3264
3 * Author: Xu Fei
4 * Time: 2010.8.13 16:21
5 * Method: 线段树
6 */
7 #include < iostream >
8 #include < cstdio >
9 using namespace std;
10
11 const int MaxN = 50001 ,INF = 0xFFFFFFF ;
12
13 struct Node
14 {
15 int a,b,ma,mi;
16 }tree[MaxN * 4 ];
17 int N,Q;
18 int A[MaxN];
19 int Max,Min;
20
21 inline int max( int a, int b) { return a > b ? a:b; }
22 inline int min( int a, int b) { return a < b ? a:b; }
23
24 void build( int num, int l, int r)
25 {
26 tree[num].a = l;
27 tree[num].b = r;
28 tree[num].ma =- INF;
29 tree[num].mi = INF;
30 if (l < r)
31 {
32 int mid = (l + r) >> 1 ;
33 build(num << 1 ,l,mid);
34 build((num << 1 ) + 1 ,mid + 1 ,r);
35 tree[num].ma = max(tree[num << 1 ].ma,tree[(num << 1 ) + 1 ].ma);
36 tree[num].mi = min(tree[num << 1 ].mi,tree[(num << 1 ) + 1 ].mi);
37 }
38 else
39 {
40 tree[num].ma = A[l];
41 tree[num].mi = A[l];
42 }
43 }
44 void query( int num, int l, int r)
45 {
46 if (tree[num].a == l && tree[num].b == r)
47 {
48 Max = max(Max,tree[num].ma);
49 Min = min(Min,tree[num].mi);
50 return ;
51 }
52 int mid = (tree[num].a + tree[num].b) >> 1 ;
53 if (r <= mid)
54 query(num << 1 ,l,r);
55 else if (l > mid)
56 query((num << 1 ) + 1 ,l,r);
57 else
58 {
59 query(num << 1 ,l,mid);
60 query((num << 1 ) + 1 ,mid + 1 ,r);
61 }
62 }
63 int main()
64 {
65 freopen( " lineupg.in " , " r " ,stdin);
66 freopen( " lineupg.out " , " w " ,stdout);
67 int i,a,b;
68 scanf( " %d%d " , & N, & Q);
69 for (i = 1 ;i <= N; ++ i)
70 scanf( " %d " ,A + i);
71 build( 1 , 1 ,N);
72 for (i = 1 ;i <= Q; ++ i)
73 {
74 scanf( " %d%d " , & a, & b);
75 Max =- INF; Min = INF;
76 query( 1 ,a,b);
77 printf( " %d\n " ,Max - Min);
78 }
79 return 0 ;
80 }
81
解法二:ST算法
DD牛解析:
另一种算法就是神奇的ST算法(Sparse Table) ,以求最大值为例,设v[n][f]表示[n,n+2^f)这个区间内的最大值,那么在询问到[a,b)区间的最大值时答案就是max(v[a] [f],v[b-2^f][f]),其中f是满足2^f<=b-a的最大的f。至于那张稀疏表,可以用递推的方法在O(nlogn)(也就是表的元 素数)的时间内构建。也就是说v[n][f]=max(v[n][f-1],v[n+2^(f-1)][f])。
1
/*
2 * Problem: USACO 2007 January Silver- lineupg PKU 3264
3 * Author: Xu Fei
4 * Time: 2010.8.12 15:38
5 * Method: ST算法
6 */
7 #include < iostream >
8 #include < cstdio >
9 using namespace std;
10
11 const int MaxN = 50010 ,MaxM = 17 ;
12
13 int N,Q;
14 int A1[MaxN][MaxM];
15 int A2[MaxN][MaxM];
16
17 inline int max( int a, int b){ return a > b ? a:b; }
18 inline int min( int a, int b){ return a < b ? a:b; }
19
20 int main()
21 {
22 freopen( " lineupg.in " , " r " ,stdin);
23 freopen( " lineupg.out " , " w " ,stdout);
24 int i,j,n,a,b,p;
25 scanf( " %d%d " , & N, & Q);
26 for (i = 0 ;i < N; ++ i)
27 {
28 scanf( " %d " , & A1[i][ 0 ]);
29 A2[i][ 0 ] = A1[i][ 0 ];
30 }
31 for (i = 1 ,j = 1 ;j < N; ++ i)
32 {
33 for (n = 0 ;; ++ n)
34 {
35 if (n + j >= N)
36 break ;
37 A1[n][i] = max(A1[n][i - 1 ],A1[n + j][i - 1 ]);
38 A2[n][i] = min(A2[n][i - 1 ],A2[n + j][i - 1 ]);
39 }
40 j = 1 << i;
41 }
42 for (i = 0 ;i < Q; ++ i)
43 {
44 scanf( " %d%d " , & a, & b);
45 -- a;
46 p = b - a;
47 for (j = 0 ;( 1 << j) <= p; ++ j);
48 -- j;
49 printf( " %d\n " ,max(A1[a][j],A1[b - ( 1 << j)][j]) -
50 min(A2[a][j],A2[b - ( 1 << j)][j]));
51 }
52 return 0 ;
53 }
54
2 * Problem: USACO 2007 January Silver- lineupg PKU 3264
3 * Author: Xu Fei
4 * Time: 2010.8.12 15:38
5 * Method: ST算法
6 */
7 #include < iostream >
8 #include < cstdio >
9 using namespace std;
10
11 const int MaxN = 50010 ,MaxM = 17 ;
12
13 int N,Q;
14 int A1[MaxN][MaxM];
15 int A2[MaxN][MaxM];
16
17 inline int max( int a, int b){ return a > b ? a:b; }
18 inline int min( int a, int b){ return a < b ? a:b; }
19
20 int main()
21 {
22 freopen( " lineupg.in " , " r " ,stdin);
23 freopen( " lineupg.out " , " w " ,stdout);
24 int i,j,n,a,b,p;
25 scanf( " %d%d " , & N, & Q);
26 for (i = 0 ;i < N; ++ i)
27 {
28 scanf( " %d " , & A1[i][ 0 ]);
29 A2[i][ 0 ] = A1[i][ 0 ];
30 }
31 for (i = 1 ,j = 1 ;j < N; ++ i)
32 {
33 for (n = 0 ;; ++ n)
34 {
35 if (n + j >= N)
36 break ;
37 A1[n][i] = max(A1[n][i - 1 ],A1[n + j][i - 1 ]);
38 A2[n][i] = min(A2[n][i - 1 ],A2[n + j][i - 1 ]);
39 }
40 j = 1 << i;
41 }
42 for (i = 0 ;i < Q; ++ i)
43 {
44 scanf( " %d%d " , & a, & b);
45 -- a;
46 p = b - a;
47 for (j = 0 ;( 1 << j) <= p; ++ j);
48 -- j;
49 printf( " %d\n " ,max(A1[a][j],A1[b - ( 1 << j)][j]) -
50 min(A2[a][j],A2[b - ( 1 << j)][j]));
51 }
52 return 0 ;
53 }
54