Problem:
Score : 2400 points

Problem Statement

Takahashi loves sorting.

He has a permutation (p_1,p_2,...,p_N) of the integers from 1 through N. Now, he will repeat the following operation until the permutation becomes (1,2,...,N):

First, we will define high and low elements in the permutation, as follows. The i-th element in the permutation is high if the maximum element between the 1-st and i-th elements, inclusive, is the i-th element itself, and otherwise the i-th element is low.

Then, let a_1,a_2,...,a_k be the values of the high elements, and b_1,b_2,...,b_{N-k} be the values of the low elements in the current permutation, in the order they appear in it.

Lastly, rearrange the permutation into (b_1,b_2,...,b_{N-k},a_1,a_2,...,a_k).

How many operations are necessary until the permutation is sorted?

Constraints

1 ≤ N ≤ 2×10^5

(p_1,p_2,...,p_N) is a permutation of the integers from 1 through N.

Input

Input is given from Standard Input in the following format:

N
p_1 p_2 ... p_N

Output

Print the number of operations that are necessary until the permutation is sorted.

Sample Input 1

5
3 5 1 2 4

Sample Output 1

3

The initial permutation is (3,5,1,2,4), and each operation changes it as follows:

In the first operation, the 1-st and 2-nd elements are high, and the 3-rd, 4-th and 5-th are low. The permutation becomes: (1,2,4,3,5).

In the second operation, the 1-st, 2-nd, 3-rd and 5-th elements are high, and the 4-th is low. The permutation becomes: (3,1,2,4,5).

In the third operation, the 1-st, 4-th and 5-th elements are high, and the 2-nd and 3-rd and 5-th are low. The permutation becomes: (1,2,3,4,5).

Sample Input 2

5
5 4 3 2 1

Sample Output 2

4

Sample Input 3

10
2 10 5 7 3 6 4 9 8 1

Sample Output 3

6

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<(b);i++)
#define RFOR(i,a,b) for (int i=(b)-1;i>=(a);i--)
#define REP(i,n) for (int i=0;i<(n);i++)
#define RREP(i,n) for (int i=(n)-1;i>=0;i--)
typedef long long LL;
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<(b);i++)
#define RFOR(i,a,b) for (int i=(b)-1;i>=(a);i--)
#define REP(i,n) for (int i=0;i<(n);i++)
#define RREP(i,n) for (int i=(n)-1;i>=0;i--)
typedef long long LL;

//根ノードを1としているので，
//左の子:k*2
//右の子:k*2+1
//親:floor(k/2)
//となる．
//根ノードを1とすると非再帰が書きやすい(二進数的性質が優れているため)のだが，
//再帰的に書くのであればどちらでも問題ない．

const int N=1<<18;//葉の個数
const int NIL = INT_MAX;

int maxi[N*2];//ノードkに対応する区間の最大値
int lazy[N*2];//lazy[k]はノードkの配下全体をlazy[k]で塗りつぶすという命令を表す．lazy[k]=NILのときは何もしないと約束する.

void setLazy(int k,int v){
     lazy[k]=lazy[k]+v;
     maxi[k]+=v;

     //***余談***
     //この発想が遅延セグメント木ではもっとも重要
     //命令がO(1)のメモリで表現でき，命令のマージが高速にできるのであれば遅延セグメント木で対処できる．
     //たとえば，区間加算と区間塗りつぶしの機能を両方備えたセグメント木を作るのであれば，
     //
     //fill v:=vで塗りつぶせ
     //add  v:=vを加算しろ
     //という二種類の命令が必要になるだろう
     //add uをした後にfill vをすることを(fill v)・(add u)と書くことにしよう．
     //この時，以下の関係式が成り立つ.
     //
     //(add v)・(add u) = (add v+u)
     //(add v)・(fill u)=(fill v+u)
     //(fill v)・(add u)=(fill v)
     //(fill v)・(fill u)=(fill v)
     //つまり add uと fill u同士の演算は(add or fill,Int)で閉じている
     //よって，命令はadd であるか fill であるかという二値情報と，加算/塗りつぶす値の2つの情報によって表現できる．
     //複数の命令を，等価な単一の命令に置き換えられるか?，と考えるとわかりやすいかも知れない
     //
     //遅延セグメント木はかならず時系列順にマージすることになる
     //これが遅延伝搬セグメント木の最大の利点と言える
     //要するに，非可換の命令を扱うのに適している
     //
     //誤解を生まないように一応書いておくが，塗りつぶしを遅延伝搬なしに書く事は不可能ではない．
     //塗りつぶした時間も保持しておけば，
     //(time S,value S)・(time T,value T)=max((timeS,valueS),(timeT,valueT))
     //として可換操作に変形できる
}

void push(int k){
   //遅延命令がなにもなければ何もしない
   if(lazy[k]==0){
      return;
   }
   
   setLazy(k*2+0,lazy[k]);
   setLazy(k*2+1,lazy[k]);
   
   //子に命令を伝搬させたので，命令を空にする
   lazy[k] =0;
}

void fix(int k){
     //ノードkに対応する区間の最大値は，「左の子の最大値」と「右の子の最大値」の最大値
     maxi[k]=max(maxi[k*2],maxi[k*2+1]);
}

//区間[queryL,queryR)にvalを足す
void add(int queryL, int queryR, int val, int k=1,int nodeL =0,int nodeR=N){
     //クエリ区間とノード区間が交差していないのなら，これ以上，処理する必要はない
     if(nodeR <= queryL || queryR<=nodeL){
        return;
     }
     //ノード区間がクエリ区間に完全に覆われたら，遅延命令をセットして，さっさと帰る
     if(queryL <= nodeL && nodeR<=queryR){
        setLazy(k,val);
        return;
     }
     //ノードが下がる時には命令をpushする
     push(k);
     int nodeM =(nodeL + nodeR) /2;
     add(queryL,queryR, val, k*2+0,nodeL, nodeM);
     add(queryL,queryR, val ,k*2+1,nodeM, nodeR);
     //ノードが上がる時には情報をfixする
     fix(k);
}

//区間[queryL,queryR)の最大値を求める
int maximum(int queryL, int queryR, int k=1,int nodeL=0,int nodeR =N){
    //クエリ区間とノード区間が交差していない
    if(nodeR<=queryL||queryR<=nodeL){
       return INT_MIN;
    }
    //ノード区間がクエリ区間に完全に覆われた
    if(queryL <= nodeL && nodeR <=queryR){
       return maxi[k];
    }
    //ノードが下がるときは命令をpushする
    push(k);
    int nodeM =(nodeL+nodeR)/2;
    int vl =maximum(queryL,queryR, k*2+0,nodeL,nodeM);
    int vr =maximum(queryL,queryR, k*2+1,nodeM,nodeR);
    fix(k);
    return max(vl,vr);
}

//初期化
void init(){
     REP(i,2*N){
         lazy[i]=0;
         maxi[i]=0;
     }
}

int M;
int p[200001];
int now[200001];
int main(){
    cin>>M;
    REP(i,M){
       cin>>p[i];
       now[p[i]]=i;
    }
    //N番目を先に処理
    init();
    int ans=1;
    /*REP(i,M){
        cout<<now[i+1]<<endl;;
    }*/
    
    add(now[M]+1,M+1,1);
    /*REP(j,M){
        cout<<maximum(j,j+1)<<" ";
    }
    cout<<endl;
    */
    for(int i=M-1;i>=2;i--){
        if(maximum(now[i+1],now[i+1]+1)==maximum(now[i],now[i]+1)){
           //同じなら後ろを塗りつぶすだけ
           add(now[i]+1,M+1,1);
        }else{
           //違うならソート回数+1
           //cout<<"Yes"<<i<<endl;
           ans++;
           if(now[i+1]<now[i]){
              add(0,now[i+1],1);
           }else{
              add(now[i]+1,now[i+1],1);
           }
           add(now[i]+1,M+1,1);
        }
        /*REP(j,M){
            cout<<maximum(j,j+1)<<" ";
        }
        cout<<endl;
        */
    }
    cout<<ans<<endl;
    
    return(0);
}