先考虑 [ 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,p2−1]最大数下标为 v 1 v_1 v1, [ p 2 + 1 , p 3 − 1 ] [p_2+1,p_3-1] [p2+1,p3−1]最大数下标为 v 2 v_2 v2
对于 p 1 p_1 p1来说,可以去左边 [ p 1 + 1 , p 2 − 1 ] [p_1+1,p_2-1] [p1+1,p2−1]中的任意一个数,右边同理
但是想满足跳跃次数最大,显然是去左边区间的 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,p2−1]的数字只能跳到本区间(两边都是最大数 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
*/