1:单调队列
/*
给出一个长度为n的序列和区间长度k
,从左向右对每一个长度为k的区间询问最大值和最小值。
思路:对于最小值,考虑维护一个递增的双端队列,每次入队时将队尾比当前入队元素的全部删除,每次取队首并且判断是否在当前区间内即可
*/
//@author:hairu,wu
//@from:ahut
#include<iostream>
#include<queue>
using namespace std;
int n,k;
int a[100100];
void solve1(){
//找出每个k区间之内的最小值
//维护一个单调递增的单调队列
deque<int> q; //保存的是单调递增的数据的下标
for(int i=1;i<=n;i++){
//维护队尾数据小于新插入的数据
while(!q.empty() && a[q.back()]>a[i] ){
q.pop_back();
}
q.push_back(i);//下标入队
if(i>=k){
//如果枚举超过k个数据,就要考虑这个大小为K的滑动窗口的最小值了
while(!q.empty() && q.front() < i+k-1){
q.pop_front();//将这个滑动窗口之前的数据弹出
}
cout<<a[q.front()]<<" ";//输出滑动窗口内的最小值
}
}
}
void solve2(){
//维护一个单调递减的单调队列
deque<int> q;
for(int i=1;i<=n;i++){
//删除队尾,保持单调递减序列
while(!q.empty() && a[q.back()]<=a[i]){
q.pop_back();
}
q.push_back(i);//插入
if(i>=k){//检测滑动窗口的最大值
while(!q.empty() && q.front()<=i-k+1){//将序列维持在滑动窗口之内
q.pop_front();
}
cout<<a[q.front()]<<endl;
}
}
}
int main(){
cin >> n>>k;
for(int i=1;i<=n;i++){
cin >> a[i];
}
solve1();
cout<<endl;
solve2();
cout<<endl;
return 0;
}
2:单调栈
//@author:hairu,wu
//@from:ahut
/*
题意:有n只奶牛排成一列向右看,每头奶牛只能看到比自己矮的奶牛,即会被高的奶牛挡住后面,
问共有多少只奶牛能被看到
思路:考虑每头奶牛能被前面牛看到的次数,也就是从他左边开始单调递减的序列的长度,
用单调栈维护即可,包括从左边到自身,必须是单调递减的
*/
#include<iostream>
#include<stack>
using namespace std;
int main(){
stack<int>s;
int n,x;
int sum=0;
cin >> n;
cin >> x;//输入第一个
s.push(x);
for(int i=1;i<n;i++){
cin >>> x;
//维护单调递减的单调栈
while(!s.empty() && s.top()<=x ){
s.pop();
}
sum+=s.size();//在未加入此元素的情况下加上左边被看的次数
s.push(x);
}
cout<<ans<<endl;
return 0;
}