单调队列就是队列中的元素是单调递增或递减的。比如把 5 2 3 1 4 入队:
减:、、、、、、、、、、、增:
5 、、、、、、、、、、、、5
5 2 、、、、、、、、、、、2
5 3 、、、、、、、、、、、2 3
5 3 1、、、、、、、、 、、1
5 4 、、、、、、、、、、、1 4
这个还是好理解的,但是,我们得会用单调队列这一特性去解决题目,抽象出题目中有类似的操作。
题意:
给你n个数a[1~n],让你输出两行数据,每行n个数。
1.对于第一行的n个数l[1~n]:把第k个数记为x,
x就是 在a[k]左边第一个比a[k]大的数 到 a[k]之间的数中(不包括这两个),最大的那个数的下标。
比如:2 5 1 2 3 4
对于 l[6],左边比他小的是 a[3]=1 a[4]=2 a[5]=3 ,a[5] 最大,所以l[6]=5;
2.对于第二行r[1~n]就是从右边开始,其他定义和第一行一样。
测试数据 :5 2 4 3 1
a[1]=5左边比他的的是a[0],a[0]到a[1]之间没有数l[1]=0;
a[2]=2左边比他的的是a[1]=5,a[1]到a[2]之间没有数,l[2]=0;
a[3]=4左边比他大的数a[1]=5,在a[1]< <a[3]之间,有一个a[2],所以l[3]=2;
a[4]=3左边比他的的是a[3]=4,a[3]到a[4]之间没有数,l[4]=0;
a[5]=1左边比他的的是a[4]=3,a[4]到a[5]之间没有数,l[5]=0;
具体的不说了,上代码,看注释呗:
#include <stdio.h>
#include <deque>
#define INF 0xfffffff
using namespace std;
int main()
{
int t,ti;
int l[50005],r[50005],a[50005];
scanf("%d",&t);
for(int ti=1;ti<=t;ti++){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
deque <int >q;
for(int i=1;i<=n;i++) //左边开始
{
int sign=1,last=0;
while(!q.empty() && a[q.back()]<a[i]) { //维护单调队列,对头的元素最大
sign=0;
last=q.back();
q.pop_back();
}
if(sign) l[i]=0; //若未弹出一个元素,则a[i-1] > a[i]
else l[i]=last; //否则,最后弹出的一个元素 必是 在比a[i]小的元素中,最大的那个
q.push_back(i);
}
for(int i=n;i>=1;i--) //右边开始,同上
{
int sign=1,last=0;
while(!q.empty() && a[q.back()]<a[i]) {
sign=0;
last=q.back();
q.pop_back();
}
if(sign) r[i]=0;
else r[i]=last;
q.push_back(i);
}
printf("Case %d:\n",ti);
for(int i=1;i<=n;i++)
printf("%d %d\n",l[i],r[i]);
}
return 0;
}