poj2823 Sliding Window
题目链接:http://poj.org/problem?id=2823
题意:
一个长度为n的序列上有一个长度为k的滑窗从左向右滑动,问每个时刻滑窗内最小值和最大值。
题解:
我们考虑单调队列。
对于维护最小值,我们维护一个单调递增的序列。新加入一个数时,弹出队尾比他大的数(因为这些数即比他大,又比他靠前,对于后面的区间来说总是不如新加入的数优)。在队首弹出(在序列中编号<该数在序列中编号-k)的数。然后记录队首即该滑窗内最小值。
最大值同理维护一个单调递减的序列即可。
#include<iostream> #include<cstdio> #include<cstring> #include<deque> #define LL long long #define RI register int using namespace std; const int INF = 0x7ffffff ; const int N = 1e6 + 10 ; inline int read() { int k = 0 , f = 1 ; char c = getchar() ; for( ; !isdigit(c) ; c = getchar()) if(c == '-') f = -1 ; for( ; isdigit(c) ; c = getchar()) k = k*10 + c-'0' ; return k*f ; } int n, m ; int a[N], hh[N], gg[N] ; deque<int>q1 ; // 递减序列维护最大值 deque<int>q2 ; // 递增序列维护最小值 deque<int>q11 ; // 维护递增序列的值在数组中的下标 deque<int>q22 ; // 维护递减序列的值在数组中的下标 int main() { n = read(), m = read() ; for(int i=1;i<=n;i++) a[i] = read() ; for(int i=1;i<m;i++) { while(q1.size() && q1.back() <= a[i]) q1.pop_back(), q11.pop_back() ; while(q2.size() && q2.back() >= a[i]) q2.pop_back(), q22.pop_back() ; q1.push_back(a[i]), q2.push_back(a[i]) ; q11.push_back(i), q22.push_back(i) ; } int cnt = 0 ; for(int i=m;i<=n;i++) { while(q1.size() && q1.back() <= a[i]) q1.pop_back(), q11.pop_back() ; while(q2.size() && q2.back() >= a[i]) q2.pop_back(), q22.pop_back() ; q1.push_back(a[i]), q2.push_back(a[i]) ; q11.push_back(i), q22.push_back(i) ; while(q11.front() <= i-m) q1.pop_front(), q11.pop_front() ; while(q22.front() <= i-m) q2.pop_front(), q22.pop_front() ; hh[++cnt] = q1.front(), gg[cnt] = q2.front() ; } for(int i=1;i<=cnt;i++) printf("%d ",gg[i]) ; printf("\n") ; for(int i=1;i<=cnt;i++) printf("%d ",hh[i]) ; return 0 ; }
update :
之前的代码有些麻烦了,更简洁的代码请看这里:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int N = 1e6 + 10 ; 8 9 inline int read() { 10 int k = 0 , f = 1 ; char c = getchar() ; 11 for( ; !isdigit(c) ; c = getchar()) 12 if(c == '-') f = -1 ; 13 for( ; isdigit(c) ; c = getchar()) 14 k = k*10 + c-'0' ; 15 return k*f ; 16 } 17 int n, m ; 18 int hh[N], q1[N], q2[N], a1[N], a2[N] ; // 单调递增维护最小值,单调递减维护最大值 ( 都维护序号 19 20 int main() { 21 n = read(), m = read() ; int h1 = 1, h2 = 1, t1 = 0, t2 = 0 ; 22 for(int i=1;i<=n;i++) hh[i] = read() ; 23 for(int i=1;i<=m;i++) { 24 while(h1 <= t1 && hh[q1[t1]] >= hh[i]) t1-- ; 25 q1[++t1] = i ; 26 while(h2 <= t2 && hh[q2[t2]] <= hh[i]) t2-- ; 27 q2[++t2] = i ; 28 } 29 int tot = 0 ; a1[++tot] = hh[q1[h1]], a2[tot] = hh[q2[h2]] ; 30 for(int i=m+1;i<=n;i++) { 31 while(h1 <= t1 && hh[q1[t1]] >= hh[i]) t1-- ; q1[++t1] = i ; 32 while(q1[h1] <= i-m) h1++ ; 33 while(h2 <= t2 && hh[q2[t2]] <= hh[i]) t2-- ; q2[++t2] = i ; 34 while(q2[h2] <= i-m) h2++ ; 35 a1[++tot] = hh[q1[h1]], a2[tot] = hh[q2[h2]] ; 36 } 37 for(int i=1;i<=tot;i++) printf("%d ",a1[i]) ; printf("\n") ; 38 for(int i=1;i<=tot;i++) printf("%d ",a2[i]) ; 39 return 0 ; 40 }