Problem:
Score: 500 points

Problem Statement

Given is a permutation P of \{1, 2, \ldots, N\}.

For a pair (L, R) (1 \le L \lt R \le N), let X_{L, R} be the second largest value among P_L, P_{L+1}, \ldots, P_R.

Find \displaystyle \sum_{L=1}^{N-1} \sum_{R=L+1}^{N} X_{L,R}.

Constraints

2 \le N \le 10^5

1 \le P_i \le N

P_i \neq P_j (i \neq j)

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
P_1 P_2 \ldots P_N

Output

Print \displaystyle \sum_{L=1}^{N-1} \sum_{R=L+1}^{N} X_{L,R}.

Sample Input 1

3
2 3 1

Sample Output 1

5

X_{1, 2} = 2, X_{1, 3} = 2, and X_{2, 3} = 1, so the sum is 2 + 2 + 1 = 5.

Sample Input 2

5
1 2 3 4 5

Sample Output 2

30

Sample Input 3

8
8 2 7 3 4 5 6 1

Sample Output 3

136

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;

#region Set

public class Set<T>
{
    Node root;
    readonly IComparer<T> comparer;
    readonly Node nil;
    public bool IsMultiSet { get; set; }

    public Set(IComparer<T> comparer)
    {
        nil = new Node(default(T));
        root = nil;
        this.comparer = comparer;
    }

    public Set(Comparison<T> comaprison) : this(Comparer<T>.Create(comaprison))
    {
    }

    public Set() : this(Comparer<T>.Default)
    {
    }

    public bool Add(T v)
    {
        return insert(ref root, v);
    }

    public bool Remove(T v)
    {
        return remove(ref root, v);
    }

    public T this[int index]
    {
        get { return find(root, index); }
    }

    public int Count
    {
        get { return root.Count; }
    }

    public void RemoveAt(int k)
    {
        if (k < 0 || k >= root.Count) throw new ArgumentOutOfRangeException();
        removeAt(ref root, k);
    }

    public T[] Items
    {
        get
        {
            var ret = new T[root.Count];
            var k = 0;
            walk(root, ret, ref k);
            return ret;
        }
    }

    void walk(Node t, T[] a, ref int k)
    {
        if (t.Count == 0) return;
        walk(t.lst, a, ref k);
        a[k++] = t.Key;
        walk(t.rst, a, ref k);
    }

    bool insert(ref Node t, T key)
    {
        if (t.Count == 0)
        {
            t = new Node(key);
            t.lst = t.rst = nil;
            t.Update();
            return true;
        }

        var cmp = comparer.Compare(t.Key, key);
        bool res;
        if (cmp > 0)
            res = insert(ref t.lst, key);
        else if (cmp == 0)
        {
            if (IsMultiSet) res = insert(ref t.lst, key);
            else return false;
        }
        else res = insert(ref t.rst, key);

        balance(ref t);
        return res;
    }

    bool remove(ref Node t, T key)
    {
        if (t.Count == 0) return false;
        var cmp = comparer.Compare(key, t.Key);
        bool ret;
        if (cmp < 0) ret = remove(ref t.lst, key);
        else if (cmp > 0) ret = remove(ref t.rst, key);
        else
        {
            ret = true;
            var k = t.lst.Count;
            if (k == 0)
            {
                t = t.rst;
                return true;
            }

            if (t.rst.Count == 0)
            {
                t = t.lst;
                return true;
            }


            t.Key = find(t.lst, k - 1);
            removeAt(ref t.lst, k - 1);
        }

        balance(ref t);
        return ret;
    }

    void removeAt(ref Node t, int k)
    {
        var cnt = t.lst.Count;
        if (cnt < k) removeAt(ref t.rst, k - cnt - 1);
        else if (cnt > k) removeAt(ref t.lst, k);
        else
        {
            if (cnt == 0)
            {
                t = t.rst;
                return;
            }

            if (t.rst.Count == 0)
            {
                t = t.lst;
                return;
            }

            t.Key = find(t.lst, k - 1);
            removeAt(ref t.lst, k - 1);
        }

        balance(ref t);
    }

    void balance(ref Node t)
    {
        var balance = t.lst.Height - t.rst.Height;
        if (balance == -2)
        {
            if (t.rst.lst.Height - t.rst.rst.Height > 0)
            {
                rotR(ref t.rst);
            }

            rotL(ref t);
        }
        else if (balance == 2)
        {
            if (t.lst.lst.Height - t.lst.rst.Height < 0) rotL(ref t.lst);
            rotR(ref t);
        }
        else t.Update();
    }

    T find(Node t, int k)
    {
        if (k < 0 || k > root.Count) throw new ArgumentOutOfRangeException();
        for (;;)
        {
            if (k == t.lst.Count) return t.Key;
            else if (k < t.lst.Count) t = t.lst;
            else
            {
                k -= t.lst.Count + 1;
                t = t.rst;
            }
        }
    }

    public int LowerBound(T v)
    {
        var k = 0;
        var t = root;
        for (;;)
        {
            if (t.Count == 0) return k;
            if (comparer.Compare(v, t.Key) <= 0) t = t.lst;
            else
            {
                k += t.lst.Count + 1;
                t = t.rst;
            }
        }
    }

    public int UpperBound(T v)
    {
        var k = 0;
        var t = root;
        for (;;)
        {
            if (t.Count == 0) return k;
            if (comparer.Compare(t.Key, v) <= 0)
            {
                k += t.lst.Count + 1;
                t = t.rst;
            }
            else t = t.lst;
        }
    }

    void rotR(ref Node t)
    {
        var l = t.lst;
        t.lst = l.rst;
        l.rst = t;
        t.Update();
        l.Update();
        t = l;
    }

    void rotL(ref Node t)
    {
        var r = t.rst;
        t.rst = r.lst;
        r.lst = t;
        t.Update();
        r.Update();
        t = r;
    }


    class Node
    {
        public Node(T key)
        {
            Key = key;
        }

        public int Count { get; private set; }
        public sbyte Height { get; private set; }
        public T Key { get; set; }
        public Node lst, rst;

        public void Update()
        {
            Count = 1 + lst.Count + rst.Count;
            Height = (sbyte) (1 + Math.Max(lst.Height, rst.Height));
        }

        public override string ToString()
        {
            return string.Format("Count = {0}, Key = {1}", Count, Key);
        }
    }
}

#endregion

public class Program
{
    private int N;
    private int[] P;

    public void Solve()
    {
        var sc = new Scanner();
        N = sc.NextInt();
        P = sc.IntArray();
        for (int i = 0; i < N; i++)
        {
            P[i]--;
        }

        var index = new int[N];

        for (int i = 0; i < N; i++)
        {
            index[P[i]] = i;
        }

        var set1 = new Set<int>();
        set1.Add(N);
        var set2 = new Set<int>((a, b) => -a.CompareTo(b));
        set2.Add(-1);
        long ans = 0;
        for (int i = N - 1; i >= 0; i--)
        {
            // iが2番目になる


            int right = set1[set1.UpperBound(index[i])];
            int left = set2[set2.UpperBound(index[i])];

            // 右側に一番がある

            if (right != N)
            {
                int rr = set1.UpperBound(right);
                int rightright = rr < set1.Count ? set1[rr] : N;
                //Console.WriteLine($"{i} {right}");
                ans += (long)(index[i] - left) * (rightright - right) * (i + 1);
            }

            // 左
            if (left != -1)
            {
                int ll = set2.UpperBound(left);
                int leftleft = ll < set2.Count ? set2[ll] : -1;
                //Console.WriteLine($"{i} {left}");
                ans += (long)(right - index[i]) * (left - leftleft) * (i + 1);
            }

            set1.Add(index[i]);
            set2.Add(index[i]);
        }

        Console.WriteLine(ans);
    }

    public static void Main(string[] args)
    {
        new Program().Solve();
    }
}

class Scanner
{
    public Scanner()
    {
        _pos = 0;
        _line = new string[0];
    }

    const char Separator = ' ';
    private int _pos;
    private string[] _line;

    #region スペース区切りで取得

    public string Next()
    {
        if (_pos >= _line.Length)
        {
            _line = Console.ReadLine().Split(Separator);
            _pos = 0;
        }

        return _line[_pos++];
    }

    public int NextInt()
    {
        return int.Parse(Next());
    }

    public long NextLong()
    {
        return long.Parse(Next());
    }

    public double NextDouble()
    {
        return double.Parse(Next());
    }

    #endregion

    #region 型変換

    private int[] ToIntArray(string[] array)
    {
        var result = new int[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = int.Parse(array[i]);
        }

        return result;
    }

    private long[] ToLongArray(string[] array)
    {
        var result = new long[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = long.Parse(array[i]);
        }

        return result;
    }

    private double[] ToDoubleArray(string[] array)
    {
        var result = new double[array.Length];
        for (int i = 0; i < array.Length; i++)
        {
            result[i] = double.Parse(array[i]);
        }

        return result;
    }

    #endregion

    #region 配列取得

    public string[] Array()
    {
        if (_pos >= _line.Length)
            _line = Console.ReadLine().Split(Separator);

        _pos = _line.Length;
        return _line;
    }

    public int[] IntArray()
    {
        return ToIntArray(Array());
    }

    public long[] LongArray()
    {
        return ToLongArray(Array());
    }

    public double[] DoubleArray()
    {
        return ToDoubleArray(Array());
    }

    #endregion
}