P1886 滑动窗口

单调队列双倍经验系列。。


这道题就是所谓的滑动窗口问题。

我们对于最大值询问,就维护一个单调递减的单调队列,队头就是最优解。

最小值同理。

注意:在队列中我们要传入每个元素进入的时间,这样才能实时从队头弹出元素,才不会WA。

有一个坑点:当\(k=1\)时,不能对第一个元素进行特殊处理。好坑啊。。。

代码:

#include<cstdio>
#include<queue>

const int maxn = 1e6 + 5;
struct Nodes
{
    int tim, val;
};
std::deque<Nodes> q;
int a[maxn], n, k;
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-') s = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return s * ans;
}
int main()
{
	//freopen("testdata.in", "r", stdin);
	//freopen("out.txt", "w", stdout);
    n = read(), k = read();
    for(int i = 1; i <= n; i++) a[i] = read();
    //q.push_back((Nodes){1, a[1]});
    for(int i = 1; i <= n; i++)
    {
    	while(!q.empty() && a[i] < q.back().val) q.pop_back();
    	q.push_back((Nodes){i, a[i]});
    	if(q.front().tim + k <= i) q.pop_front();
    	if(i >= k) printf("%d ", q.front().val);
	}
	printf("\n");
	q.clear();
	//q.push_back((Nodes){1, a[1]});
	for(int i = 1; i <= n; i++)
	{
		while(!q.empty() && a[i] > q.back().val) q.pop_back();
		q.push_back((Nodes){i, a[i]});
		if(q.front().tim + k <= i) q.pop_front();
		if(i >= k) printf("%d ", q.front().val);
	}
	printf("\n");
    return 0;
}
posted @ 2018-08-24 13:26  Garen-Wang  阅读(165)  评论(0编辑  收藏  举报