openjudge滑動視窗(單調遞增遞減佇列)
阿新 • • 發佈:2019-02-06
滑動視窗(from openjudge)
在解決這個問題的時候,會碰到超時的問題。在資料量很大的情況下,不難想到需要用
所謂遞增(遞減)佇列想要實現的就是佇列中的元素是有序排列的。在一開始我們會想要直接利用STL庫中的優先佇列實現這個事情,但是問題在於我們難以進入到優先佇列的中間進行操作,只能對頭和尾進行操作,在面對這個題裡面對於視窗長度的限制的時候很難完成任務,所以我們選擇自己實現一個雙端佇列的遞增(遞減)佇列結構。
這個結構模擬一個佇列,利用val儲存資料,front代表隊列頭,back代表隊列尾,在佇列為空的時候 ront=back
在處理的過程中,需要注意以下兩個問題:
1. 因為是對陣列中的數字操作,為了實現判斷數字是否在視窗之內,我們在佇列中儲存的是數字在陣列中的索引(具體可看程式碼實現)
2. 注意在實現從隊首、隊尾操作過程中的邊界判斷( ack
程式碼實現如下
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2000000;
int num[N/2]; /*儲存輸入資料*/
int ansup[N/2]; /*儲存視窗中的大元素答案*/
int ansdown[N/2]; /*儲存視窗中的小元素答案*/
//遞減佇列,找大元素
struct QueueUp {
int val[N];
int window;
int front, back;
QueueUp(int w) {
window = w;
front = 0;
back = 0;
}
//x傳入的是在num中的索引
int push(int x) {
//佇列為空
if (front == back) {
val[front] = x;
back++;
return x;
}
int tmp = num[x];
//刪掉視窗外的元素
while (front < back && x - val[front] >= window)
front++;
//刪掉從末尾開始的小元素
while (back - 1 >= front && tmp >= num[val[back - 1]])
back--;
val[back] = x;
back++;
return val[front];
}
};
//遞增佇列,找小元素
struct QueueDown {
int val[N];
int window;
int front, back;
QueueDown(int w){
window = w;
front = back = 0;
}
//x傳入的是在num中的索引
int push(int x) {
if (front == back) {
val[front] = x;
back++;
return x;
}
int tmp = num[x];
while (front < back && x - val[front] >= window)
front++;
while (back - 1 >= front && tmp <= num[val[back - 1]])
back--;
val[back] = x;
back++;
return val[front];
}
};
int main()
{
int n, k;
cin >> n >> k;
QueueDown down(k);
QueueUp up(k);
for (int i = 0; i < k - 1; i++) {
scanf("%d", num + i);
up.push(i);
down.push(i);
}
int count = 0;
for (int i = k - 1; i < n; i++) {
scanf("%d", num + i);
ansdown[count] = down.push(i);
ansup[count] = up.push(i);
count++;
}
for (int i = 0; i < count; i++)
printf("%d ", num[ansdown[i]]);
cout << endl;
for (int i = 0; i < count; i++)
printf("%d ", num[ansup[i]]);
cout << endl;
return 0;
}
至此完結~~