luogu-单调队列/单调栈专题
下面所有单调队列和单调栈,我使用的 双端队列 STL 的 deque 模拟操作
题意:
给出水滴的坐标与下落时间,你需要构造一个盆,使他的宽度满足
在其范围内能够接住水滴时间(第一滴和最后一滴/最大与最小值)时间差大于等于k,且使得这个盆的直径最小
思路:
会想到尺取法(双指针)来在符合条件内缩小范围,同时又涉及到区间最值问题,那么上来想就很容易想到单调队列或者单调栈来维护区间最值
两点:满足区间最小与最大之差大于k,且使得其长度最小。
(1)区间最值:由于是要进行双指针操作:所以选择双端队列来实现单调队列维护最值,且能维护在 q.front().x ~ q.back().x的区间最值
(2)在符合条件下对 front/队首进行移动,以达到缩小区间操作
code:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+7; const int inf = 0x3f3f3f3f; struct node{ int x,y; }; bool cmp(node a,node b){ return a.x<b.x; } node arr[maxn]; deque<node>q1; deque<node>q2; int main(){ int n,k; cin>>n>>k; for(int i=0;i<n;i++){ cin>>arr[i].x>>arr[i].y; } sort(arr,arr+n,cmp); int ans = inf; for(int i=0;i<n;i++){ node tmp; //维护最大最小单调队列 while(!q1.empty()&&q1.back().y<arr[i].y) q1.pop_back(); tmp = arr[i]; q1.push_back(tmp); while(!q2.empty()&&q2.back().y>arr[i].y) q2.pop_back(); q2.push_back(tmp); while(!q1.empty()&&!q2.empty()&&q1.front().y-q2.front().y>=k){ node pos; if(q1.front().x<q2.front().x) {pos = q1.front(); q1.pop_front();} else {pos = q2.front(); q2.pop_front();} ans = min(ans,arr[i].x-pos.x); } } if(ans!=inf) cout<<ans<<endl; else cout<<-1<<endl; }
题意:给出n个珠子,m种颜色( 用1~m的序号表示 ),然后给出每种颜色的珠子的个数以及位置,选择出最小的区间 涵盖所有颜色种类的珠子。
思路:(这道题感觉和单调队列/栈没啥关系)尺取法,如果被新放入的位置使得涵盖了所有的颜色,就对尾部进行收缩,减小其长度。
code:
//把所有的颜色全部包含的最小长度 #include <bits/stdc++.h> using namespace std; const int maxn = 1e6+5; const int inf = 0x3f3f3f3f; int cont[maxn]; struct node{ int pos,color; }nodes[maxn]; bool cmp(node a,node b){ return a.pos<b.pos; } deque<node>q1;//滑动窗口 int main(){ int n,m; cin>>n>>m; int cnt = 0; memset(cont,0,sizeof(cont)); for(int i=1;i<=m;i++){ int t; cin>>t; while(t--){ int tmp; cin>>tmp; nodes[cnt++] = (node){tmp,i}; } } sort(nodes,nodes+cnt,cmp); int tot = 0; int ans = inf; for(int i =0;i<cnt;i++){ //操作:如果所有颜色全部被包含就尝试缩短长度 //如何有效判断颜色被全部包含?设置tot,用于统计当前颜色总数 //如果颜色在序列中大于1则pop出去 q1.push_back(nodes[i]); cont[nodes[i].color]++; //如果是新增加的颜色提供的贡献 if(cont[nodes[i].color]==1) tot++; while(!q1.empty()&&cont[q1.front().color]>1){ cont[q1.front().color]--; if(cont[q1.front().color]<1) tot--; q1.pop_front(); } if(tot==m) ans = min(ans,(q1.back().pos-q1.front().pos)); } cout<<ans<<endl; return 0; }