Link

先考虑 [ 1 , n ] [1,n] [1,n]区间中最大的那些数字 m x mx mx,这些数字把 [ 1 , n ] [1,n] [1,n]分成若干个小区间

考虑 a p 1 = a p 2 = a p 3 = m x & & p 1 < p 2 < p 3 a_{p_1}=a_{p_2}=a_{p_3}=mx\&\&p_1<p_2<p_3 ap1=ap2=ap3=mx&&p1<p2<p3

[ p 1 + 1 , p 2 − 1 ] [p_1+1,p_2-1] [p1+1,p21]最大数下标为 v 1 v_1 v1, [ p 2 + 1 , p 3 − 1 ] [p_2+1,p_3-1] [p2+1,p31]最大数下标为 v 2 v_2 v2

对于 p 1 p_1 p1来说,可以去左边 [ p 1 + 1 , p 2 − 1 ] [p_1+1,p_2-1] [p1+1,p21]中的任意一个数,右边同理

但是想满足跳跃次数最大,显然是去左边区间的 v 1 v_1 v1或者去右边区间的 v 2 v_2 v2比较好

不妨让 p 2 p_2 p2 v 1 , v 2 v_1,v_2 v1,v2连一条边

然后因为 [ p 1 + 1 , p 2 − 1 ] [p_1+1,p_2-1] [p1+1,p21]的数字只能跳到本区间(两边都是最大数 m x mx mx)

又是一个递归的子问题,我们一直这样连边下去

最后会形成一个 D A G DAG DAG,而且这个 D A G DAG DAG非常特殊,类似一颗多叉树

可以预处理每个节点的深度, x , y x,y x,y两点深度差就是最大值

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
int n,m,h[maxn],dep[maxn],ans[maxn],mx[maxn][22],lg[maxn];
int Max(int a,int b){ return h[a]>=h[b]?a:b; }
int get(int l,int r)
{
    int k = lg[r-l+1];
    return Max( mx[l][k],mx[r-(1<<k)+1][k] );
}
int dfs(int l,int r,int depth)
{
    if( l>r )   return -1;
    int p = get(l,r); dep[p] = depth;
    ans[p] = dfs( l,p-1,depth+1 )+1;
    int nowmx = ans[p];
    while( p<r )
    {
        int q = get( p+1,r );
        if( h[p]!=h[q] )    break;
        dep[q] = depth;
        int temp = dfs( p+1,q-1,depth+1)+1;
        nowmx = max( nowmx,temp );
        ans[p] = max( ans[p],temp );
        ans[q] = temp; p = q;
    }
    ans[p] = max( ans[p],dfs( p+1,r,depth+1 )+1 );
    nowmx = max( nowmx,ans[p] );
    return nowmx;
}
int main()
{
    cin >> n >> m;
    for(int i=1;i<=n;i++)   cin >> h[i], mx[i][0] = i;
    for(int i=2;i<=n;i++)   lg[i] = lg[i>>1]+1;
    for(int i=1;i<=20;i++)
    for(int j=1;j+(1<<i)-1<=n;j++)
        mx[j][i] = Max( mx[j][i-1],mx[j+(1<<(i-1))][i-1] );
    dfs( 1,n,0 );
    while( m-- )
    {
        int l,r; cin >> l >> r;
        if( !r )    cout << ans[l] << "\n";
        else
        {
            if( h[l]<h[r] ) swap( l,r );
            if( l==r )  cout << 0 << "\n";
            else
            {
                int id;
                if( l<r )   id = get( l+1,r );
                else    id = get( r,l-1 );
                if( h[l]<=h[id] )   cout << 0 << "\n";
                else    cout << dep[r]-dep[l] << "\n";
            }
        }
    }
}
/*
12 8
2 3 4 4 4 3 3 3 1 2 5 2
3 0
4 0
5 0
7 0
7 11
7 9
11 1
9 12
*/