using System;
using System.Collections.Generic;//list用
using System.Text;//StringBuilder用
using System.Collections;//ハッシュテーブル用
using System.Linq;

class Program
{
    //Hashtable ht = new Hashtable();
    static List<int> A = new List<int>();
    static decimal result;
    static int N,K;
    //StringBuilder strresult= new StringBuilder("");//Append(str ○○)関数で文字を追加していく

    static void Main()
    {
        //Modular mo = new Modular(0);//素数で割った余りを出せで使う。()内が初期値。★使い方：Modular型で宣言すると、その時点でのその素数で割った余りを保持する変数になる（powべき乗、Fac累乗、nCr組み合わせも関数として存在）
        //Node no = new Node<>();//UnionFind★Find関数で根っこの値を返す（根っこの値が一緒なら同グループ）、Unite関数で二つの木をくっつける
        //Permutation pe = new Permutation<>();//配列＆リストを並べ替えた場合の全ケースを出力★All関数でリスト形式で返す。
        Treap<int> tr = new Treap<int>();//平衡二分木★Insert()関数で挿入、FindIndex()関数で該当する大きさの物が入るべき配列番号を返す。
        // delegate int CFunc();//下関数に使うデリゲータ。コイツと同じ引数と戻り値で関数作って、下の評価式の部分に関数名を入れる。
        PriorityQueue<int,int> pr = new PriorityQueue<int,int>();//優先度付キュー★Add(key,value)で格納、Dequeue()で取りだし。keyが小さいものから取り出す。
        Read1();
        Read2(N);
      //★素直にやると10^5の三重ループになるので計算過多。ループを何とか１重に。
      //各値について、全体を見て自分より大きな数字をセーブして、それをピッタリ１跨ぎする（自分より大きいのが１コだけある）区間が、答えがその数になる区間といえる。
//なので、（求めた区間の数）*（自分自身）を足しこんで行けば答えが出る。
      int before2,before1,after1,after2;
      decimal num;
      int k;
      int count=0;
      //優先キューで、大きなものから処理するように並べ替える。（＝処理済みの場所がそのまま跨ぎカウントの場所となるため、跨ぎ箇所を毎回探査しなくて済む）
      for(int i=0;i<N;i++){pr.Add(-A[i],i);}
      for(int i=0;i<N;i++){
        k=pr.Dequeue().Value;
        //初期の区切り位置は、配列の外の部分
      before2=-1;before1=-1;after1=N;after2=N;num=0;
        if(i==0){}else{
         int ind=tr.FindIndex(k);
        //前方チェック

        if(ind<=0){}
        else if(ind==1){
        before2=tr[ind-1];
        }
        else{
        before2=tr[ind-1];
          before1=tr[ind-2];
        }
//後方チェック
if(ind>=count){}
        else if(ind==count-1){
        after2=tr[ind];
        }
        else{
        after2=tr[ind];
          after1=tr[ind+1];
        }
        }
        num+=(before2-before1)*(after2-k);
        num+=(after1-after2)*(k-before2);

        result+=num*(A[k]);
                tr.Insert(k);count++;//二分木を使って、現在地の最傍の処理済み（大きなもの）を低コストで探せるようにする
      }

        Console.WriteLine(result.ToString());
    }


    static void Read1()
    {
        string tmp = Console.ReadLine();
        N = int.Parse(tmp);
    }

    static void Read2(int kosuu)
    {
        string[] tmp = Console.ReadLine().Split(' ');
      for(int i=0;i<N;i++){A.Add(int.Parse(tmp[i]));}
    }

}



class PriorityQueue<TKey, TValue>
{
    SortedDictionary<TKey, Queue<TValue>> dict = new SortedDictionary<TKey, Queue<TValue>>();
    int count = 0;

    public int Count
    {
        get
        {
            return count;
        }
    }

    public void Add(TKey key, TValue value)
    {
        if (!dict.ContainsKey(key))
        {
            dict[key] = new Queue<TValue>();
        }

        dict[key].Enqueue(value);
        count++;
    }

    public KeyValuePair<TKey, TValue> Dequeue()
    {
        var queue = dict.First();
        if (queue.Value.Count <= 1)
        {
            dict.Remove(queue.Key);
        }
        count--;
        return new KeyValuePair<TKey, TValue>(queue.Key, queue.Value.Dequeue());
    }
}
    class Treap<T> where T : IComparable
    {
        private class Node
        {
            private static Random g_rand = new Random();
            private readonly int m_rank = g_rand.Next();
            private readonly T m_value;
            private Node m_lch;
            private Node m_rch;
            private int m_count;

            public Node(T value)
            {
                m_value = value;
                m_count = 1;
            }

            private static int Count(Node node)
            {
                return (node != null) ? node.m_count : 0;
            }

            private Node Update()
            {
                m_count = Count(m_lch) + Count(m_rch) + 1;
                return this;
            }

            public static Node Merge(Node a, Node b)
            {
                if (a == null) { return b; }
                if (b == null) { return a; }

                if (a.m_rank < b.m_rank)
                {
                    a.m_rch = Merge(a.m_rch, b);
                    return a.Update();
                }
                else
                {
                    b.m_lch = Merge(a, b.m_lch);
                    return b.Update();
                }
            }

            public static Tuple<Node, Node> Split(Node t, int k)
            {
                if (t == null) { return new Tuple<Node, Node>(null, null); }

                if (k <= Count(t.m_lch))
                {
                    var pair = Split(t.m_lch, k);
                    t.m_lch = pair.Item2;
                    return new Tuple<Node, Node>(pair.Item1, t.Update());
                }
                else
                {
                    var pair = Split(t.m_rch, k - Count(t.m_lch) - 1);
                    t.m_rch = pair.Item1;
                    return new Tuple<Node, Node>(t.Update(), pair.Item2);
                }
            }

            public int FindIndex(T value)
            {
                int L = Count(m_lch);
                if (value.CompareTo(m_value) < 0)
                {
                    return (m_lch != null) ? m_lch.FindIndex(value) : 0;
                }
                else if (value.CompareTo(m_value) > 0)
                {
                    return (m_rch != null) ? m_rch.FindIndex(value) + L + 1 : L + 1;
                }
                else
                {
                    return L;
                }
            }

            public T this[int i]
            {
                get
                {
                    int L = Count(m_lch);
                    if (i < L)
                    {
                        return m_lch[i];
                    }
                    else if (i > L)
                    {
                        return m_rch[i - L - 1];
                    }
                    else
                    {
                        return m_value;
                    }
                }
            }
        }

        private Node node;

        public void Insert(T value)
        {
            if (node != null)
            {
                int k = node.FindIndex(value);
                var pair = Node.Split(node, k);
                node = Node.Merge(Node.Merge(pair.Item1, new Node(value)), pair.Item2);
            }
            else
            {
                node = new Node(value);
            }
        }

        public int FindIndex(T value)
        {
            return node.FindIndex(value);
        }

        public T this[int i]
        {
            get
            {
                return node[i];
            }
        }
    }



Measured memory_bytes: 42196