单调队列 | 线段树 | 一维RMQ —— POJ 2823

来源:互联网 发布:c语言打开文件并写入 编辑:程序博客网 时间:2024/06/11 10:03

对应POJ题目:点击打开链接

Sliding Window
Time Limit: 12000MS Memory Limit: 65536KTotal Submissions: 42356 Accepted: 12503Case Time Limit: 5000MS

Description

An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example: 
The array is [1 3 -1 -3 5 3 6 7], and k is 3.Window positionMinimum valueMaximum value[1  3  -1] -3  5  3  6  7 -13 1 [3  -1  -3] 5  3  6  7 -33 1  3 [-1  -3  5] 3  6  7 -35 1  3  -1 [-3  5  3] 6  7 -35 1  3  -1  -3 [5  3  6] 7 36 1  3  -1  -3  5 [3  6  7]37

Your task is to determine the maximum and minimum values in the sliding window at each position. 

Input

The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line. 

Output

There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values. 

Sample Input

8 31 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 33 3 5 5 6 7

题意:给出n个数,求从左往右每k个数的最值。


思路1:单调队列

        可在队首和队尾删除元素,在队尾插入元素。以递增队列(即队首元素最小,队列严格递增)为例,队尾删除元素:从队尾往前扫,一直pop掉不比e小的元素,e入队;队首删除元素:当队尾元素跟队首元素在原数组里的距离大于k时,就删除队首元素。

如本例:1  3  -1  -3  5  3  6  7

                0  1  2   3   4  5  6  7

1、(1,0)

2、(1,0)(3,1)

3、(-1,2)

4、(-3,3)

5、(-3,3)(5,4)

6、(-3,3)(3,5)

7、(3,5)(6,6)//这里在加入(6,6)时把(-3,3)pop掉是因为6和-3这两个元素的距离len = 4 > k

8、(3,5)(6,6,)(7,7)

由于每一次入队都保证了队首元素为最小值,所以从第k次开始,每一次的队首元素就是样例输出的最小值。最大值求法类似。


思路2:线段树。就是线段树的区间最值


思路3:RMQ。

使用二维RMQ肯定超内存。由于题目区间长度固定,所以可以用滚动数组的方法,所以使用一维就可以了。可以有两种表示方法:

1)dp[i]表示从下标i开始数的长度为2^m个数的最值,其中2^m 为小于k的最大值。

2)dp[i]表示代替原来的dp[i][j](dp[i][j]表示从下标i开始数的长度为2^j个数的最值,其中2^j 为小于k的最大值。


思路4:堆~(这部分知识待补)


优化:听说可以在I/O流中做文章,即缓存输入与无缓存输入(这部分知识待补


单调队列:

#include <stdio.h>#include <stdlib.h>#include <string.h>#define M 1000005int a[M];int que[M];int front, rear;int p[M];int fp, rp;#define Front          que[front]#define Rear           que[rear-1]#define Push(x, i)     que[rear++] = x, p[rp++] = i#define Pop            front++, fp++#define Pop_back       rear--, rp--#define Clearque       front = rear = fp = rp = 0#define Lengthque      p[rp-1] - p[fp] + 1#define Emptyque       (front == rear ? 1 : 0)void SolveMin(int *A, int n, int k){int i;front = rear = fp = rp = 0;for(i = 0; i < n; i++){if(Emptyque && A[i] < Front) Clearque;else while(Rear >= A[i] && !Emptyque) Pop_back;Push(A[i], i);if(Lengthque > k) Pop;if(i >= k - 1){printf("%d", Front);if(i < n - 1) printf(" ");}}printf("\n");}void SolveMax(int *A, int n, int k){int i;front = rear = fp = rp = 0;for(i = 0; i < n; i++){if(Emptyque && A[i] > Front) Clearque;else while(Rear <= A[i] && !Emptyque) Pop_back;Push(A[i], i);if(Lengthque > k) Pop;if(i >= k - 1){printf("%d", Front);if(i < n - 1) printf(" ");}}printf("\n");}int main(){//freopen("in.txt", "r", stdin);int n, k;int i, j;while(~scanf("%d%d", &n, &k)){for(i = 0; i < n; i++)scanf("%d", &a[i]);SolveMin(a, n, k);SolveMax(a, n, k);}}

线段树:

#include <stdio.h>#include <stdlib.h>#include <string.h>#define M 1000005#define MAX(x, y) ((x) > (y) ? (x) : (y))#define MIN(x, y) ((x) < (y) ? (x) : (y))int a[M];int Max[M<<2];int Min[M<<2];int B[M];int S[M];typedef struct{int b, s;}Point;void Build(int root, int left, int right){if(left == right - 1){Max[root] = Min[root] = a[left];return;}int mid = (left + right)>>1;Build(root<<1, left, mid);Build(root<<1|1, mid, right);Max[root] = MAX(Max[root<<1], Max[root<<1|1]);Min[root] = MIN(Min[root<<1], Min[root<<1|1]);}Point Query(int root , int left, int right, int l, int r){Point P, P1;if(l <= left && right <= r){P.b = Max[root];P.s = Min[root];return P;}int mid = (left + right)>>1;int b1, b2;if(r <= mid) return Query(root<<1, left, mid, l, r);else if(l >= mid) return Query(root<<1|1, mid, right, l, r);else{P = Query(root<<1, left, mid, l, mid);P1 = Query(root<<1|1, mid, right, mid, r);Point p;p.b = MAX(P.b, P1.b);p.s = MIN(P.s, P1.s);return p;}}int main(){//freopen("in.txt", "r", stdin);int n, k, u;int i;while(~scanf("%d%d", &n, &k)){for(i = 0; i < n; i++)scanf("%d", &a[i]);Build(1, 0, n);u = 0;Point P;for(i = 0; i + k <= n; i++){P = Query(1, 0, n, i, i + k);B[u] = P.b;S[u++] = P.s;}printf("%d", S[0]);for(i = 1; i < u; i++)printf(" %d", S[i]);printf("\n");printf("%d", B[0]);for(i = 1; i < u; i++)printf(" %d", B[i]);printf("\n");}}

一维RMQ(1):

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#define M 1010000#define MAX(x, y) ((x) > (y) ? (x) : (y))#define MIN(x, y) ((x) < (y) ? (x) : (y))int Max[M];int Min[M];int main(){//freopen("in.txt", "r", stdin);int n, k, val;int i, j, limit;while(~scanf("%d%d", &n, &k)){for(i = 0; i < n; i++){scanf("%d", &val);Max[i] = Min[i] = val;}for(j = 1; (j<<1) < k; j <<= 1)for(i = 0; i + (j<<1) - 1 < n; i++){Max[i] = MAX(Max[i], Max[i+j]);Min[i] = MIN(Min[i], Min[i+j]);}printf("%d", MIN(Min[0], Min[k-j]));for(i = 1; i + k -1 < n; i++){printf(" %d", MIN(Min[i], Min[i+k-j]));}printf("\n");printf("%d", MAX(Max[0], Max[k-j]));for(i = 1; i + k -1 < n; i++){printf(" %d", MAX(Max[i], Max[i+k-j]));}printf("\n");}}
一维RMQ(2):
#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#define M 1000005#define MAX(x, y) ((x) > (y) ? (x) : (y))#define MIN(x, y) ((x) < (y) ? (x) : (y))int a[M];int Max[M];int Min[M];void caldp(int n, int limit)  {  int i, j;int r1, r2;    for(i=0; i<n; i++)        Max[i] = Min[i] = a[i];     for(j=1; j<=limit; j++){ //注意这个要在外层        for(i=0; i<n; i++){            if(i+(1<<j)-1 < n){                //Max[i][j] = MAX(Max[i][j-1], Max[i+(1<<(j-1))][j-1]);                  //Min[i][j] = MIN(Min[i][j-1], Min[i+(1<<(j-1))][j-1]);                  Max[i] = MAX(Max[i], Max[i+(1<<(j-1))]);                  Min[i] = MIN(Min[i], Min[i+(1<<(j-1))]);              }          }      }  }    int rmq_max(int limit, int l, int r)  {      return MAX(Max[l], Max[r-(1<<limit)+1]);}  int rmq_min(int limit, int l, int r)  {      return MIN(Min[l], Min[r-(1<<limit)+1]);  }  int main(){//freopen("in.txt", "r", stdin);int n, k, u;int i, limit;while(~scanf("%d%d", &n, &k)){for(i = 0; i < n; i++)scanf("%d", &a[i]);limit = log(double(k)) / log(2.0);caldp(n, limit);  printf("%d", rmq_min(limit, 0, k - 1));for(i = 1; i + k <= n; i++){printf(" %d", rmq_min(limit, i, i + k - 1));}printf("\n");printf("%d", rmq_max(limit, 0, k - 1));for(i = 1; i + k <= n; i++){printf(" %d", rmq_max(limit, i, i + k - 1));}printf("\n");}}



0 0
原创粉丝点击