title: 专题3 - 单调栈、单调队列
tags: [单调队列]
categories: [OI, 算法专题]
单调栈其实是单调队列的一种特殊情况,所以我们只看单调队列。
单调队列包含两端:过期端和淘汰端。
队列内从过期端到淘汰端,权值越来越小,进队时间越来越短。
本质上是在队列中存可能在现在/将来称为答案的节点,权值(价值)最高的点在过期端头,入队时间长且价值低的点将被剔除。
元素可以不为入队时间,也就是说可以针对任意两个元素的信息处理。
直接看代码:
#include <bits/stdc++.h>
using namespace std;
//#define int long long
#define REP(i,a,b) for(int i=(a);i<=(b);i++)
int n,k;
int a[1000100];
deque <int> q;
signed main(){
cin >> n >>k;
REP(i,1,n) cin >> a[i];
REP(i,1,n){
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) q.pop_front();
printf("%d ",a[q.front()]);
}
}
printf("\n");
while (!q.empty()) q.pop_front();
REP(i,1,n){
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) q.pop_front();
printf("%d ",a[q.front()]);
}
}
return 0;
}
习题
P2698 USACO12MAR Flowerpot S
原题 · 标签:#单调队列 #二分
考点
单调队列经典建模与应用
题意
有 \(N\) 个水滴,坐标为 \((x,y)\),每个水滴每秒向下移动1单位,落到x轴的时间等于自身纵坐标 \(y\)。
将花盆放在x轴上(一段连续区间),水滴落点 \(x\) 在区间内就会被接住。
要求:被接住的水滴中,最大下落时间 - 最小下落时间 ≥ D,求满足条件的花盆最小宽度;无法满足则输出 \(-1\)。
数据范围
- \(1 \le N \le 10^5\)
- \(1 \le D \le 10^6\)
- \(0 \le x,y \le 10^6\)
思路
首先很好想到二分,两个元素,宽度看做过期指标(y轴),时间看做权值(x轴),就很显然了。
两个元素,有过期信息和最值信息的处理,单调队列!
使用单调队列维护宽度窗口内的最大值和最小值,check是否大于等于D,在外面二分宽度。
代码
// 1
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define f(i,a,b) for(int i=(a);i<=(b);i++)
#define ll long long
#define pii pair<int,int>
#define DEBUG 0
#if DEBUG
#define d(x) cout << #x << " = " << x << endl;
#define da(a,l,r) cout << #a << "[" << l << "-" << r << "]:"; f(i,l,r) cout << a[i] << " "; cout << endl;
#else
#define d(x)
#define da(a,l,r)
#endif
struct ddzSt{
int x,y;
bool operator < (ddzSt st2){
return y < st2.y;
}
};
int n,nd;
vector<ddzSt> s;
struct DdzMaxQ{
vector<int> q;
int head,tail;
void init(int size){
q.resize(size+2);
head=1;tail=0;
}
void push(int idx,const vector<ddzSt>& nums){
while(head<=tail && nums[q[tail]].y <= nums[idx].y) tail--;
q[++tail]=idx;
}
void popUntil(int left){
while(head<=tail && q[head]<left) head++;
}
int getY(const vector<ddzSt>& nums){
return nums[q[head]].y;
}
};
struct DdzMinQ{
vector<int> q;
int head,tail;
void init(int size){
q.resize(size+2);
head=1;tail=0;
}
void push(int idx,const vector<ddzSt>& nums){
while(head<=tail && nums[q[tail]].y >= nums[idx].y) tail--;
q[++tail]=idx;
}
void popUntil(int left){
while(head<=tail && q[head]<left) head++;
}
int getY(const vector<ddzSt>& nums){
return nums[q[head]].y;
}
};
DdzMaxQ qMax;
DdzMinQ qMin;
bool check(int mid){
qMax.init(n);
qMin.init(n);
int left=1;
f(i,1,n){
qMax.push(i,s);
qMin.push(i,s);
while(s[i].x - s[left].x > mid) left++;
qMax.popUntil(left);
qMin.popUntil(left);
if(qMax.getY(s) - qMin.getY(s) >= nd) return 1;
}
return 0;
}
bool cmp(ddzSt a,ddzSt b){
return a.x < b.x;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> nd;
s.resize(n+1);
f(i,1,n){
cin >> s[i].x >> s[i].y;
}
sort(s.begin()+1,s.end(),cmp);
int lef=0,rig=1e6,ans=-1;
while(lef<=rig){
int mid=(lef+rig)/2;
if(check(mid)){
ans=mid;
rig=mid-1;
}
else lef=mid+1;
}
cout << ans;
return 0;
}
浙公网安备 33010602011771号