【題目大意】
給你一個長度不超過1e6的序列,現在有一個數字k,表示長度爲k的子序列自左到右滑動時保持長度爲k。
現在要求出該長度爲k區間在滑動的過程中區間的最大值最小值。
【解題思路】
如果此題直接模擬或者利用最大值的單調性來做的話,在長度爲k的區間上無法保證次大值的正確性。
本題的正確的思路是單調隊列。
首先求出每次滑動的最小值。
我們考慮維護一個下標隊列,首先將前k的數直接加入隊列。
然後用一個指針從k+1位掃到最後一位,遇到的數如果比要插入的數大,則刪除隊尾元素,將指針前移,重複操作知道該元素遇到一個比它大的元素,或隊列爲空。
記住保存到一定是下標。
然後重複以上操作求出最大值(將條件改爲“遇到的數如果比要插入的數小”)
【代碼】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cctype>
#include<iomanip>
#define LL long long
//#define LOCAL
using namespace std;
namespace output{
char ch[1000];
}
const int N=1000011;
int n,m,k;
int head,tail;
int q[N];
int a[N];
inline int CIN(){
int num=0;
int f=1;
char c=getchar();
while ((c>'9'||c<'0')&&c!='-') c=getchar();
if (c=='-'){
f=-1;
c=getchar();
}
while (c>='0'&&c<='9'){
num=(num<<3)+(num<<1)+c-'0';
c=getchar();
}
return f*num;
}
inline void COUT(int x){
if (x==0){
putchar(48);
return;
}
if (x<0){
putchar('-');
x=-x;
}
char *s=output::ch;
while (x){
*(++s)=x%10;
x/=10;
}
while (s!=output::ch) putchar((*(s--))+48);
}
struct humdrum{//下標隊列
int q[N];
bool exist[N];
int zjl;
void Insert_Max(int x){
while (tail>=head&&a[q[tail]]<=a[x]) exist[q[tail--]]=false;
q[++tail]=x;
exist[x]=true;
}
void Insert_Min(int x){
while (tail>=head&&a[q[tail]]>=a[x]) exist[q[tail--]]=false;
q[++tail]=x;
exist[x]=true;
}
void Delete(int x){
if (exist[x]) head++;
}
void Clear(){
memset(exist,false,sizeof(exist));
memset(q,0,sizeof(q));
zjl=0;
}
}que;
int main(){
#ifdef LOCAL
freopen("POJ2823.in","r",stdin);
#endif
while (scanf("%d%d",&n,&k)!=EOF){
que.Clear();
head=0;
tail=-1;
for (int i=1;i<=n;++i) a[i]=CIN();
for (int i=1;i<=k;++i) que.Insert_Min(i);
COUT(a[que.q[head]]);
putchar(' ');
for (int i=k+1;i<=n;++i){
que.Insert_Min(i);
que.Delete(i-k);
if (i!=n) COUT(a[que.q[head]]),putchar(' ');
else COUT(a[que.q[head]]),putchar('\n');
}
que.Clear();
head=0;
tail=-1;
for (int i=1;i<=k;++i) que.Insert_Max(i);
COUT(a[que.q[head]]);
putchar(' ');
for (int i=k+1;i<=n;++i){
que.Insert_Max(i);
que.Delete(i-k);
if (i!=n) COUT(a[que.q[head]]),putchar(' ');
else COUT(a[que.q[head]]),putchar('\n');
}
}
return 0;
}
【總結】
單調隊列,單調棧可以優化很多問題,務必掌握!