#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
//typedef long double ld;

typedef map<int, int> mii;
typedef pair<int, int> pii;
typedef pair<double,double> pdd;
typedef set<int> si;
typedef set<ll> sll;
typedef vector<int> vi;
typedef vector<pair<int, int > > vii;
typedef vector<ll> vll;
typedef vector<double> vd;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
typedef vector<vll> vvll;

constexpr ll MOD = 1e9+7;
constexpr int INF = 1<<30;
constexpr ll  LINF = 1LL<<60;

#define Sort(x) sort(x.begin(),x.end())
#define Reverse(x) reverse(x.begin(),x.end())
#define ABS(a,b) ((a)<(b)?(b)-(a):(a)-(b))
#define nbit(n) (1ll<<(n))

// sort(begin(x), end(x), greater<ll>());
// lower_bound(a.begin(), a.end(), val): a[i] ≥ valである最左の位置
// upper_bound(a.begin(), a.end(), val): a[i] > valである最左の位置

// Returns minimum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmin(T& a, T b) {
  if (a > b) {
    a = b;
  }
  return a;
}

// Returns maximum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmax(T& a, T b) {
  if (a < b) {
    a = b;
  }
  return a;
}

// a = (a+b)%MOD;
void addmod(ll& a, ll b) {
  a = (a+b)%MOD;
}

template <typename T>
void dumpContents(const T& v, const string& msg)
{
  cerr << "### " << msg << " ###\n";
  for (const auto& x : v) {
    cerr << x << " ";
  }
  cerr << endl;
}

struct before_main_function {
  before_main_function() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout<<setprecision(20)<<fixed;
    #define endl "\n"
  }
} before_main_function;

template <typename T>
class SegmentTree {
private:
  using F = function<T(T,T)>; // min or max

  F f;
  T ti; // 単位元 (INF for min or -INF for max)

  int n;
  vector<T> dat;

  // Find a minimum in [a,b).
  // A node k corresponds to a range [l,r) in the segment tree.
  // So, the initial query should be query(a, b, 0, 0, n)
  T query(const int a, const int b, const int k, const int l, const int r) {
     // 1) No cross between [a,b) and [l, r)
     if (r<=a || b<=l) {
       return ti;
     }

     // 2) [a,b) includes [l ,r)
     if (a <= l && r <= b) return dat[k];

     // 3) otherwise
     const T vl = query(a, b, k*2+1, l, (l+r)/2);
     const T vr = query(a, b, k*2+2, (l+r)/2, r);
     return f(vl, vr);
  }

public:
  SegmentTree(F _f, T _ti)
    : f(_f), ti(_ti) {}

  void init(int n_) {
    // Set n to power of 2
    n = 1;
    while (n < n_) n *= 2;

    dat.resize(2*n-1);
    fill(begin(dat), end(dat), ti);
  }

  void build(const vector<T>& v) {
    const int n_ = v.size();
    init(n_);

    for(int i=0; i<n_; i++) dat[i+n-1] = v[i];
    for(int i=n-2; i>=0 ;i--)
      dat[i] = f(dat[i*2+1], dat[i*2+2]);
  }

  // Update the value of the k-th node (zero indexed) to a.
  void update(int k, T a) {
    k += n-1;
    dat[k] = a;
    // Climbing up the tree
    while (k>0) {
      k = (k-1)/2;
      dat[k] = f(dat[k*2+1], dat[k*2+2]);
    }
  }

  // Find a minimum or maximum in [a,b).
  T query(const int a, const int b) {
    return query(a, b, 0, 0, n);
  }

};

// ========== end of template ==========
int N;
vll P;

vii lefts;  // first: next, second: next,next
vii rights;

int main(int argc, char** argv) {
  cin >> N;
  P.resize(N);
  for (int i=0; i<N; i++) {
    cin >> P[i];
  }

  lefts.resize(N);
  rights.resize(N);

  {
    // Range Maximam Query
    SegmentTree<ll> rmq(
            [](ll a, ll b) {
              return max(a, b);
            },
            -INF);
    rmq.init(N+1);

    // Look left
    for (int i=0; i<N; i++) {
      int x = rmq.query(P[i]+1, N+1);
      if (x < 0) {
        lefts[i] = {-1, -1};
      } else {
        int y = rmq.query(P[i]+1, P[x]);
	y = max({y, lefts[x].first});
	y = y<0 ? -1 : y;
        lefts[i] = {x, y};
      }

      rmq.update(P[i], i);
    }
  }

  // Look right
  {
    // Range Minimum Query
    SegmentTree<ll> rmq(
            [](ll a, ll b) {
              return min(a, b);
            },
            INF);
    rmq.init(N+1);

    // Look right
    for (int i=N-1; i>=0; i--) {
      int x = rmq.query(P[i]+1, N+1);
      if (x >= N) {
        rights[i] = {N, N};
      } else {
        int y = rmq.query(P[i]+1, P[x]);
	y = min({y, rights[x].first});
	y = y>=N ? N : y;
        rights[i] = {x, y};
      }

      rmq.update(P[i], i);
    }

//    for (int i=0; i<N; i++) {
//      cerr << rights[i].first << "," << rights[i].second << "  ";
//    }
//    cerr << endl;
  }

  ll ret = 0;
  for (int i=0; i<N; i++) {
    // Look left
    // 自分が現状2番
    if (lefts[i].first >= 0) {
      int l2 = lefts[i].first;
      int l1 = lefts[i].second + 1;
      int r1 = i;
      int r2 = rights[i].first-1;
      // [l1, l2] - [r1-r2]
      //
      ret += P[i]*(l2-l1+1)*(r2-r1+1);
//cerr << "(2) " << P[i] << ": " << l1 << " - " << l2 << "  " << r1 << " - " << r2 << endl;
    }

    // 自分が現状1番
    int l = lefts[i].first+1;
    int r1 = rights[i].first; // 自分が2番に落ちる
    if (r1<N) {
      int r2 = rights[i].second-1;
      // [l,i] - [r1,r2]
      ret += P[i]*(i-l+1)*(r2-r1+1);
//cerr << "(1) " << P[i] << ": " << l << " - " << i << "  " << r1 << " - " << r2 << endl;
    }
  }

  cout << ret << endl;

  return 0;
}


Measured memory_bytes: 4608