用数组du作为单调队列,把对应a中的下标记录下来。l和r分别是数组du的左右界。以求区间最大为例,如果后来的元素更大,则前面比它小的元素就没机会成为最大了,直接去掉。若后来的元素更小,由于位序偏后,可能会成为某个区间的最大。当区间里的数多于k个,就把最前面的元素去掉。最终du对应a中的元素单调下降,最前面的元素a[du[l]]就是最大。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll a[1000010];
int du[1000010];//记录区间的第i个数在a中的下标
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin >> n >> k;
for(int i=0;i<n;i++)
cin >> a[i];
int l=0;
int r=1;//左闭右开的区间
//du是单调队列,存放在a中的下标
du[0]=0;//最开始的元素下标为0
if(k==1) cout << a[0] << " ";//保证a的首元素会被输出
for(int i=1;i<n;i++){//遍历a中元素
if(i-du[l]>=k) l++;
while(a[du[r-1]]>=a[i] && r>l) r--;//注意左闭右开,du最后一位是r-1
du[r++]=i;
if(i>=k-1) cout << a[du[l]] << " ";
}
cout << "\n";
l=0;
r=1;//左闭右开的区间
//du是单调队列,存放在a中的下标
du[0]=0;//最开始的元素下标为0
if(k==1) cout << a[0] << " ";
for(int i=1;i<n;i++){//遍历a中元素
if(i-du[l]>=k) l++;
while(a[du[r-1]]<=a[i] && r>l) r--;
du[r++]=i;
if(i>=k-1) cout << a[du[l]] << " ";
}
cout << "\n";
return 0;
}
京公网安备 11010502036488号