九度OJ 1544 数字序列区间最小值
题目地址:http://ac.jobdu.com/problem.php?pid=1544
- 题目描述:
-
给定一个数字序列,查询任意给定区间内数字的最小值。
- 输入:
-
输入包含多组测试用例,每组测试用例的开头为一个整数n(1<=n<=100000),代表数字序列的长度。
接下去一行给出n个数字,代表数字序列。数字在int范围内。
下一行为一个整数t(1<=t<=10000),代表查询的次数。
最后t行,每行给出一个查询,由两个整数表示l、r(1<=l<=r<=n)。
- 输出:
-
对于每个查询,输出区间[l,r]内的最小值。
- 样例输入:
-
5 3 2 1 4 3 3 1 3 2 4 4 5
- 样例输出:
-
1 1 3
An <O(N), O(sqrt(N))> solution
#include <stdio.h> #include <math.h> #include <limits.h> void Preprocess (int arr[], int n, int loc[]){ int i, j, k; int step; int min; step = (int)sqrt((double)n); i = j = k = 0; while (1){ min = k*step; for (j=k*step+1; j<n && j<(k+1)*step; ++j){ if (arr[min] > arr[j]) min = j; } loc[k] = min; ++k; if (j >= n) break; } } int main(void){ int n; int arr[100001]; int loc[1000]; int t; int i; int left; int right; int min; int step; int index; while (scanf ("%d", &n) != EOF){ step = (int)sqrt((double)n); for (i=0; i<n; ++i){ scanf ("%d", &arr[i]); } Preprocess (arr, n, loc); scanf ("%d", &t); while (t-- != 0){ scanf ("%d%d", &left, &right); --left; --right; min = INT_MAX; while (left <= right && left % step != 0){ if (arr[left] < min){ min = arr[left]; } ++left; } while (left + step <= right){ index = loc[left/step]; if (arr[index] < min){ min = arr[index]; } left += step; } while (left <= right){ if (arr[left] < min){ min = arr[left]; } ++left; } printf ("%d\n", min); } } return 0; } /************************************************************** Problem: 1544 User: 简简单单Plus Language: C Result: Accepted Time:330 ms Memory:1252 kb ****************************************************************/
Sparse Table (ST) algorithm
//Sparse Table (ST) algorithm #include <stdio.h> #include <math.h> #include <limits.h> #define MAX 100000 #define LOGMAX 20 void Preprocess (int M[MAX][LOGMAX], int arr[MAX], int n){ int i, j; for (i = 0; i < n; ++i) M[i][0] = i; for (j = 1; 1 << j <= n; ++j){ for (i = 0; i + (1 << j) - 1 < n; ++i){ if (arr[M[i][j - 1]] < arr[M[i + (1 << (j - 1))][j - 1]]) M[i][j] = M[i][j - 1]; else M[i][j] = M[i + (1 << (j - 1))][j - 1]; } } } int main(void){ int n; int arr[MAX]; int M[MAX][LOGMAX]; int test; int left; int right; int i; int min; int k; while (scanf ("%d", &n) != EOF){ for (i = 0; i < n; ++i){ scanf ("%d", &arr[i]); } Preprocess (M, arr, n); scanf ("%d", &test); while (test-- != 0){ scanf ("%d%d", &left, &right); --left; --right; k = 0; while ((1 << (k + 1)) < (right - left + 1)) ++k; if (arr[M[left][k]] <= arr[M[right - (1 << k) + 1][k]]) min = arr[M[left][k]]; else min = arr[M[right - (1 << k) + 1][k]]; printf ("%d\n", min); } } return 0; } /************************************************************** Problem: 1544 User: 简简单单Plus Language: C Result: Accepted Time:270 ms Memory:9040 kb ****************************************************************/
Segment trees
#include <stdio.h> #include <math.h> #define MAX 100000 #define MAXN 200000 void Initialize (int node, int b, int e, int M[MAXN], int arr[MAX], int n){ if (b == e){ M[node] = b; } else{ //compute the values in the left and right subtrees Initialize(2 * node, b, (b + e) / 2, M, arr, n); Initialize(2 * node + 1, (b + e) / 2 + 1, e, M, arr, n); //search for the minimum value in the first and //second half of the interval if (arr[M[2 * node]] <= arr[M[2 * node + 1]]) M[node] = M[2 * node]; else M[node] = M[2 * node + 1]; } } int Query(int node, int b, int e, int M[MAXN], int arr[MAX], int i, int j) { int p1, p2; //if the current interval doesn't intersect //the query interval return -1 if (i > e || j < b) return -1; //if the current interval is included in //the query interval return M[node] if (b >= i && e <= j) return M[node]; //compute the minimum position in the //left and right part of the interval p1 = Query(2 * node, b, (b + e) / 2, M, arr, i, j); p2 = Query(2 * node + 1, (b + e) / 2 + 1, e, M, arr, i, j); //return the position where the overall //minimum is if (p1 == -1) //return M[node] = p2; return p2; if (p2 == -1) //return M[node] = p1; return p1; if (arr[p1] <=arr[p2]) return p1; return p2; } int main(void){ int n; int arr[MAX]; int M[MAXN]; int t; int left; int right; int i; int index; while (scanf ("%d", &n) != EOF){ for (i = 0; i < n; ++i){ scanf ("%d", &arr[i]); } for (i=0; i<MAXN; ++i){ M[i] = -1; } Initialize (1, 0, n - 1, M, arr, n); scanf ("%d", &t); while (t-- != 0){ scanf ("%d%d", &left, &right); --left; --right; index = Query(1, 0, n - 1, M, arr, left, right); printf ("%d\n", arr[index]); } } return 0; } /************************************************************** Problem: 1544 User: 简简单单Plus Language: C Result: Accepted Time:290 ms Memory:2016 kb ****************************************************************/
参考资料:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor
http://dongxicheng.org/structure/lca-rmq/
http://dongxicheng.org/structure/segment-tree/