您的位置:首页 > 其它

POJ2823 经典单调队列

2019-07-29 12:11 20 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_40534166/article/details/97631726

POJ2823 单调队列

题目地址poj.org/problem?id=2823

视频讲解地址https://www.bilibili.com/video/av23189029?from=search&seid=7739016115400904464

给你一个长度为N的数组,一个长为K滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位。你的任务是找出窗口在各位置时的最大值和最小值。

单调队列具有队列内所有元素不是单调递增就是单调递减的性质,所以每次的最小(最大)值一定会在队首。

程序实现过程中先将前k个元素入队,此后每次在队尾加入a[k+1…n],在插入元素中同时进行以下操作:

1、将队尾所有大于a[i]的值弹出队列

2、插入a[i]到队尾

3、判断队首元素位置是否超出i-k

就找出各个区间的最大值来说,一个数值较大且位置靠后的元素会更有用,这个数是区间最大值的可能性更大,因此要将比新加入的数小的数踢出队列。

具体做法可以建立两个双端队列分别用来处理区间最大值和区间最小值。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<cstdlib>
using namespace std;
#define scan(n) scanf("%d",&n)
#define ll long long

struct node
{
int pos,val;
}a;
deque<node>maxq,minq;
int ma[1000005],mi[1000005];
int main()
{
int n,k,x,i;
scan(n);
scan(k);
while(!maxq.empty())
maxq.pop_back();
while(!minq.empty())
minq.pop_back();
for(i=1;i<k;i++)
{
scanf("%d",&x);
while(!maxq.empty()&&maxq.back().val<=x)
maxq.pop_back();
while(!minq.empty()&&minq.back().val>=x)
minq.pop_back();
a.pos=i,a.val=x;
maxq.push_back(a);
minq.push_back(a);
}
for(i=k;i<=n;i++)
{
while(!maxq.empty()&&maxq.front().pos<i-k+1)//先踢掉超出范围的
maxq.pop_front();
while(!minq.empty()&&minq.front().pos<i-k+1)
minq.pop_front();
scanf("%d",&x);
while(!maxq.empty()&&maxq.back().val<=x)//再踢掉非最优解
maxq.pop_back();
while(!minq.empty()&&minq.back().val>=x)
minq.pop_back();
a.pos=i,a.val=x;
maxq.push_back(a);
minq.push_back(a);
ma[i]=maxq.front().val;
mi[i]=minq.front().val;
}
printf("%d",mi[k]);
for(i=k+1;i<=n;i++)
printf(" %d",mi[i]);
printf("\n");

printf("%d",ma[k]);
for(i=k+1;i<=n;i++)
printf(" %d",ma[i]);
printf("\n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: