题目链接:https://www.luogu.org/problem/show?pid=1886
题目描述
现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如:
The array is [1 3 -1 -3 5 3 6 7], and k = 3.
输入输出格式
输入格式:
输入一共有两行,第一行为n,k。
第二行为n个数(<INT_MAX).
输出格式:
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
输入输出样例
说明
50%的数据,n<=10^5
100%的数据,n<=10^6
这道题是一个单调队列的简单应用,下面是程序:
#include<stdio.h>
#include<iostream>
using namespace std;
const int N=1000005;
struct node{
int s,x;
node(){};
node(int a,int b){
s=a;
x=b;
}
};
template<typename T>
struct queue{
T a[N];
int l,r;
void clear(){
l=0,r=1;
}
bool empty(){
return l+1==r;
}
T front(){
return a[(l+1)%N];
}
T back(){
return a[(r+N-1)%N];
}
void push_front(T x){
a[l]=x;
l=(l+N-1)%N;
}
void push_back(T x){
a[r]=x;
r=(r+1)%N;
}
void pop_front(){
l=(l+1)%N;
}
void pop_back(){
r=(r+N-1)%N;
}
};
queue<node>q[2];
int ans[N];
inline int read(){
int s=0,f=1;
char c=getchar();
while((c<'0'||c>'9')&&c!='-'){
c=getchar();
}
if(c=='-'){
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
s*=10;
s+=c-'0';
c=getchar();
}
return s*f;
}
int main(){
int n,k,i,x;
n=read();
k=read();
q[0].clear();
q[1].clear();
for(i=0;i<k;i++){
x=read();
while(!q[0].empty()&&q[0].back().s>=x){
q[0].pop_back();
}
q[0].push_back(node(x,i));
while(!q[1].empty()&&q[1].back().s<=x){
q[1].pop_back();
}
q[1].push_back(node(x,i));
}
printf("%d ",q[0].front().s);
ans[0]=q[1].front().s;
for(;i<n;i++){
x=read();
while(!q[0].empty()&&q[0].back().s>=x){
q[0].pop_back();
}
q[0].push_back(node(x,i));
while(q[0].front().x<=i-k){
q[0].pop_front();
}
printf("%d ",q[0].front().s);
while(!q[1].empty()&&q[1].back().s<=x){
q[1].pop_back();
}
q[1].push_back(node(x,i));
while(q[1].front().x<=i-k){
q[1].pop_front();
}
ans[i-k+1]=q[1].front().s;
}
putchar('\n');
for(i=0;i<=n-k;i++){
printf("%d ",ans[i]);
}
return 0;
}