单调队列为什么要开一个记录编号的数组

P1886 滑动窗口 /【模板】单调队列

Calanosay @ 2021-03-28 12:04:17

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int q[maxn],k,n,a[maxn],p[maxn];
void solve(){
    int head=1,tail=0;
    memset(q,0,sizeof(q));
    for(int i=1;i<=n;i++){
        while(head<=tail&&a[i]>=q[tail])    tail--;
        q[++tail]=a[i];
        p[tail]=i;
        while(p[head]<=i-k) head++;
        if(i>=k)    printf("%d ",q[head]);
    }
}
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
    solve();
} 

上面的是正确代码,求最大值的

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int q[maxn],k,n,a[maxn],p[maxn];
void solve(){
    int head=1,tail=0;
    memset(q,0,sizeof(q));
    for(int i=1;i<=n;i++){
        while(head<=tail&&a[i]>=q[tail])    tail--;
        q[++tail]=a[i];
        while(head<=i-k)    head++;
        if(i>=k)    printf("%d ",q[head]);
    }
}
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
    solve();
} 

这是我的代码,没有用p数组存储tail的下标,因为我感觉tail本身就是一个编号一样的东西,比如tail=7就证明tail现在在7号位置,请问我的想法错在哪里


by zimujun @ 2021-03-28 12:41:37

while(head<=tail&&a[i]>=q[tail])    tail--;

tail 是会减的,再加入新的数之后原来从队尾弹出的是不能放回去的


by zimujun @ 2021-03-28 12:42:43

另外,其实只需要开一个队列存下标,存原数的队列其实反而不必要。

因为你存了下标之后可以直接在原数组中用下标来找原数


by Calanosay @ 2021-03-28 12:55:08

@zimujunqwq 哇,巨型抽象,我或许又得研究几个小时了


by Calanosay @ 2021-03-28 13:02:28

@zimujunqwq 不对啊,你不存原数的话,岂不是要输入一次处理一次


by zimujun @ 2021-03-28 13:05:09

@Fucker_Chao

原来的数组是要记录的啊

我的意思是说你可以只开一个存下标的队列


|