【洛谷P1886】滑动窗口——单调队列
没想到啊没想到,时隔两个月,我单调队列又懵了……
调了一个小时,最后错在快读,啊!!!!(不过洛谷讨论真好啊,感谢大佬!)
考前就不推新东西了,好好写写那些学过的东西
题目点这里(我就不粘了自己点一下看吧)
这题还有其他奇奇怪怪的做法,比如你可以当做RMQ,用线段树啊ST表啊随便你,不过单调队列就可以了
单调队列说到底就是个数据结构,就是维护数据的。
以当前这道题为例:
它维护的队列一定满足单调性,单调递增或递减,或者自定义一个单调性。
如何维护呢,假设当前队尾为q [ tail ], 要插入元素为 a [ i ]
- 若直接插入 a [ i ] 满足其单调性,就直接插入
- 若不满足,就删掉 q [ tail ] ( tail - - ) ,因为能取到 q [ tail ] 就一定能取到 a [ i ] , 而a [ i ] 更优
这题既然要求最大值和最小值,就求两遍嘛!
下面是代码
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int n,k,a[1000001],q[1000001],p[1000001],head,tail; inline int read() { int x=0; char c=getchar(); int flag=1; while (c>'9'||c<'0') { if (c=='-') flag*=-1; c=getchar(); } //就是这里!!!!记住它!!! while (c<='9'&&c>='0') x=x*10+c-48,c=getchar(); x*=flag; return x; }//这个坑死我的快读啊!!!!!!考前一定要多打几遍 int main() { n=read(); k=read(); for (int i=1; i<=n; i++) a[i]=read(); // 求 min head=1; tail=0; for (int i=1; i<=n; i++) { while (head<=tail&&q[tail]>=a[i]) tail--; //首先保证不要删过,head<=tail(tail可以等于head) //求最小那么单调性就是单调递增 q[++tail]=a[i]; p[tail]=i;//插入队列 while (p[head]<=i-k) head++;//更新队头,使最值在区间内 if (i>=k) cout<<q[head]<<" ";//k往后每一个i都对应一个窗口,输出队头存储的最值即可 } cout<<endl; head=1,tail=0; // 求 max ,类比求 min for (int i=1; i<=n; i++) { while (head<=tail&&q[tail]<=a[i]) tail--; //最大值就是单调递增 q[++tail]=a[i]; p[tail]=i; while (p[head]<=i-k) head++; if (i>=k) cout<<q[head]<<" "; } return 18751214;//快考试啦不要抄答案!!!(给我自己 }
就是这些,CSP快到啦,RP++!!
惯例