您的位置:首页 > 其它

[单调队列] POJ2823

2017-09-09 17:22 148 查看
找出范围内的最大和最小

第一次接触单调队列(保证队列单调性)

放一下方法(因为明天一定会忘光光的hhh)

开始很不理解为什么队列要把比新插入的数小的数全部删除

但这道题只要最大值就没追究了

也是能保持头部的index永远是最小的一个关键

判断改成head<=end 后就不是WA了

但g++还是TLE,C++是AC

参考:http://blog.csdn.net/justmeh/article/details/5844650

假设数列为:8,7,12,5,16,9,17,2,4,6.N=10,k=3.
那么我们构造一个长度为3的单调递减队列:
首先,那8和它的索引0放入队列中,我们用(8,0)表示,每一步插入元素时队列中的元素如下:
0:插入8,队列为:(8,0)
1:插入7,队列为:(8,0),(7,1)
2:插入12,队列为:(12,2)
3:插入5,队列为:(12,2),(5,3)
4:插入16,队列为:(16,4)
5:插入9,队列为:(16,4),(9,5)

1.首先看插入元素:为了保证队列的递减性,我们在插入元素v的时候,要将队尾的元素和v比较,如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾。

2.队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于i-k+1的时候,就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首元素删除。

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 3500000
using namespace std;

int n, k;
int Num[ N ]; //输入

struct Node {
int val, idx;
} Que[ N ];

void GetMax () {
memset ( Que, 0, sizeof ( Que ) );
int head = 0; //保存头部位置
int end = -1; //保存尾部位置

for ( int i = 1; i <= n; i++ ) {
Node tmp;
tmp.val = Num[ i ];
tmp.idx = i;

while ( head <= end && Que[ end ].val <= Num[ i ] ) // 1.去掉尾部比新加入元素小的
end--;
Que[ ++end ] = tmp;

while ( head <= end && Que[ head ].idx < i - k + 1 ) // 2.去掉头部index超过范围的
head++;

if ( i >= k ) {
if ( i != k )
printf ( " " );
printf ( "%d", Que[ head ] );
}
}
printf ( "\n" );
}

void GetMin () {
memset ( Que, 0, sizeof ( Que ) );
int head = 0;
int end = -1;

for ( int i = 1; i <= n; i++ ) {
Node tmp;
tmp.val = Num[ i ];
tmp.idx = i;

while ( head <= end && Que[ end ].val >= Num[ i ] )
end--;
Que[ ++end ] = tmp;

while ( head <= end && Que[ head ].idx < i - k + 1 )
head++;

if ( i >= k ) {
if ( i != k )
printf ( " " );
printf ( "%d", Que[ head ] );
}
}
printf ( "\n" );
}

int main () {
while ( cin >> n && cin >> k ) {
for ( int j = 1; j <= n; j++ )
scanf ( "%d", &Num[ j ] );
GetMin ();
GetMax ();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: