POJ 2823 Sliding Window

这是一道单调队列的题目,做这道题目也是为了理解单调队列到底是什么东西,下面是摘自百度百科的一段说明,说的明不明白呢,只可意会不可言传~

单调队列查询为O(1)。

进队出队稍微复杂点:
进队时,将进队的元素为e,从队尾往前扫描,直到找到一个不大于e的元素d,将e放在d之后,舍弃e之后的所有元素;如果没有找到这样一个d,则将e放在队头(此时队列里只有这一个元素)。
出队时,将出队的元素为e,从队头向后扫描,直到找到一个元素f比e后进队,舍弃f之前所有的。(实际操作中,由于是按序逐个出队,所以每次只需要出队只需要比较队头)。
每个元素最多进队一次,出队一次,摊排分析下来仍然是 O(1)。
上面的话可能还是没能讲出单调队列的核心:队列并不实际存在的,实际存在的是具有单调性的子序列。对这个子序列按心中的队列进行操作,譬如在进队时丢弃的元素,虽然它不存在于这个子序列里,但是还是认为他存在于队列里


在这个题中,我们建立两个分别递增和递减的队列increase和decrease。以increase队列为例,当输入一个新的元素时,从队尾开始寻找,如果队尾元素大于num是把队尾元素删除,直到第一个不大于它的元素,在该元素后插入。另外对距离大于k的元素要从队列中删除。

代码如下,在提交我已经用了input挂居然还是过不了poj的G++,后来改C++一下就过了,看来优化还不够啊



#include <iostream>
#include <cstdio>

using namespace std;
const int M = 1000005;
struct Node
{
	int m,d;
}increase[M],decrease[M];

int num,mi[M],ma[M];
int head_in,tail_in,head_de,tail_de,top;

int input()
{
	char in;
	bool isn = false;
	int num;
	in = getchar();
	while(in != '-' && (in < '0'||in > '9'))
		in = getchar();
	if(in == '-'){ isn = true;num = 0;}
	else num = in - '0';
	while(in = getchar(),in >= '0' && in <= '9')
	{
		num *= 10;
		num += in - '0';
	}
	if(isn) num = -num;
	return num;
}

int main()
{
	int n,k;
	scanf("%d%d",&n,&k);
	head_in = tail_in = head_de = tail_de = top = 0;
	//scanf("%d",&num);
	num = input();
	increase[0].m = decrease[0].m = num;
	increase[0].d = decrease[0].d = 0;
	for(int i = 1;i < k;i++)
	{
		//scanf("%d",&num);
		num = input();
		while(increase[tail_in].m > num && tail_in >= head_in) tail_in--;
		tail_in++;
		increase[tail_in].d = i;
		increase[tail_in].m = num;
		while(decrease[tail_de].m < num && tail_de >= head_de) tail_de--;
		tail_de++;
		decrease[tail_de].d = i;
		decrease[tail_de].m = num;
	}
	mi[top] = increase[head_in].m;
	ma[top++] = decrease[head_de].m;
	for(int i = k;i < n;i++)
	{
		//scanf("%d",&num);
		num = input();
		while(increase[tail_in].m > num && tail_in >= head_in) tail_in--;
		tail_in++;
		increase[tail_in].d = i;
		increase[tail_in].m = num;
		while(i - increase[head_in].d + 1 > k)head_in++;
		while(decrease[tail_de].m < num && tail_de >= head_de) tail_de--;
		tail_de++;
		decrease[tail_de].d = i;
		decrease[tail_de].m = num;
		while(i - decrease[head_de].d + 1 > k)head_de++;
		mi[top] = increase[head_in].m;
		ma[top++] = decrease[head_de].m;
	}
	for(int i = 0;i < top-1;i++)
		printf("%d ",mi[i]);
	printf("%d\n",mi[top-1]);
	for(int i = 0;i < top-1;i++)
		printf("%d ",ma[i]);
	printf("%d\n",ma[top-1]);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值