暂时只考虑 m a x ( a i , a j ) < m i n ( a i + 1 , . . . , a j − 1 ) max(a_i,a_j)
说人话就是 [ i + 1 , j − 1 ] [i+1,j-1] [i+1,j−1]的所有数都大于 a i a_i ai和 a j a_j aj
考 虑 维 护 一 个 单 调 递 增 的 栈 考虑维护一个单调递增的栈 考虑维护一个单调递增的栈
在 这 个 单 增 栈 中 的 位 置 p o s , 如 果 a [ p o s ] > a j 在这个单增栈中的位置pos,如果a[pos]>a_j 在这个单增栈中的位置pos,如果a[pos]>aj
那 么 [ p o s + 1 , j − 1 ] 一 定 都 是 大 于 a p o s 的 那么[pos+1,j-1]一定都是大于a_{pos}的 那么[pos+1,j−1]一定都是大于apos的
因 为 如 果 存 在 一 个 x 使 得 a x < = a p o s , 加 入 a x 会 弹 出 a p o s 因为如果存在一个x使得a_x<=a_{pos},加入a_x会弹出a_{pos} 因为如果存在一个x使得ax<=apos,加入ax会弹出apos
所 以 现 在 不 就 证 明 了 位 置 p o s 合 法 嘛 所以现在不就证明了位置pos合法嘛 所以现在不就证明了位置pos合法嘛
只 需 要 在 维 护 单 增 栈 弹 栈 弹 的 就 是 那 些 p o s , 顺 便 转 移 一 下 就 好 了 只需要在维护单增栈弹栈弹的就是那些pos,顺便转移一下就好了 只需要在维护单增栈弹栈弹的就是那些pos,顺便转移一下就好了
另 一 种 情 况 就 是 要 求 [ i + 1 , j − 1 ] 所 有 数 都 小 于 a i 和 a j 另一种情况就是要求[i+1,j-1]所有数都小于a_i和a_j 另一种情况就是要求[i+1,j−1]所有数都小于ai和aj
那 同 样 维 护 一 个 单 调 递 减 的 栈 那同样维护一个单调递减的栈 那同样维护一个单调递减的栈
如 果 a p o s < a j , 那 么 说 明 [ p o s + 1 , j − 1 ] 都 是 小 于 a p o s 的 如果a_{pos}
同 样 转 移 即 可 同样转移即可 同样转移即可
#include
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[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];
}