暂时只考虑
max(ai,aj)<min(ai+1,...,aj−1)这一种转移
说人话就是
[i+1,j−1]的所有数都大于
ai和
aj
考虑维护一个单调递增的栈
在这个单增栈中的位置pos,如果a[pos]>aj
那么[pos+1,j−1]一定都是大于apos的
因为如果存在一个x使得ax<=apos,加入ax会弹出apos
所以现在不就证明了位置pos合法嘛
只需要在维护单增栈弹栈弹的就是那些pos,顺便转移一下就好了
另一种情况就是要求[i+1,j−1]所有数都小于ai和aj
那同样维护一个单调递减的栈
如果apos<aj,那么说明[pos+1,j−1]都是小于apos的
同样转移即可
#include <bits/stdc++.h>
using namespace std;
const int maxn=8e5+10;
int n,a[maxn];
int down[maxn],up[maxn],top1,top2,f[maxn];
int main()
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
down[++top1]=1,up[++top2]=1;
f[0]=1e9;
for(int i=2;i<=n;i++)
{
f[i]=f[i-1]+1;
while( top2&&a[i]<a[up[top2]] )
f[i]=min( f[i],f[up[top2--]]+1 );
while( top1&&a[i]>a[down[top1]] )
f[i]=min( f[i],f[down[top1--]]+1 );
f[i]=min( f[i],min( f[down[top1]],f[up[top2]] )+1 );//这里是第一个大于a[i]或小于a[i],可以转移
while( a[down[top1]]==a[i] ) top1--;//相等是不能转移的
while( a[up[top2]]==a[i] ) top2--;
down[++top1]=i,up[++top2]=i;
}
cout << f[n];
}