单调队列

单调队列的特点,一个是严格单调性(不是非递增或者非递减),这样方便求区间最值;另外一个就是队头队尾都可以出队,但是只有队尾能入队,这个特点是为了保证队列内没有区间外的元素。常见应用,区间求最值,还有动态规划的优化处理。

POJ2823 Sliding Windo,就是典型的求区间最值问题,单调队列可解

CODE:

#include<stdio.h>
//const int N = 1000001;
#define N 1000001
int num[N],que[N];

int main()
{
	int i,n,k;
	int head,tail;
	scanf("%d%d",&n,&k);
	for(i=0;i<n;i++){
		scanf("%d",&num[i]);
	}
	
	head=0,tail=0;
	que[0]=0;
	for(i=0;i<k;i++){//前3个特殊处理,避免重复输出
		//队列que中保存的是数组元素下标;因为要找的是区间最小值,所以维护队列的严格递增,也就是说,即将操作的
		//元素必须大于队尾元素才能入队,否则队尾元素一直出队,直到队尾元素小于即将操作的数,或者队列为空
		while(num[ que[tail] ]>=num[i] && head<=tail)
			tail--;
		que[++tail] = i;
	}
	printf("%d ",num[ que[head] ]);
	for(;i<n;i++){
		while(num[ que[tail] ]>=num[i] && head<=tail)
			tail--;
		que[++tail]=i;
		while(i-que[head] >= k)//距离差距超过k的话,队头出队,直到队列长度不超过k
			head++;
		if(i!=n-1)
			printf("%d ",num[ que[head] ]);
	}
	printf("%d\n",num[ que[head] ]);
	
	
	/*找的是区间最大值,所以维护的是队列的严格递减,其余跟上面一样*/
	head=0,tail=0;
	que[0]=0;
	for(i=0;i<k;i++){
		while(num[ que[tail] ]<=num[i] && head<=tail)
			tail--;
		que[++tail] = i;
	}
	printf("%d ",num[ que[head] ]);
	for(;i<n;i++){
		while(num[ que[tail] ]<=num[i] && head<=tail)
			tail--;
		que[++tail]=i;
		while(i-que[head] >= k)//距离差距超过k的话,队头出队,直到队列长度不超过k
			head++;
		if(i!=n-1)
			printf("%d ",num[ que[head] ]);
	}
	printf("%d\n",num[ que[head] ]);
	return 0;
}


你可能感兴趣的:(优化,ini)