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: Wrong Answer)

#if DEBUG
using Microsoft.VisualStudio.TestTools.UnitTesting;
#endif

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace Contest
{
    class Program
    {
        static void Main(string[] args)
        {
            var scanner = new IO.StreamScanner(Console.OpenStandardInput());
            var n = scanner.Integer();
            var p = scanner.ScanLine().Split().Select(v => int.Parse(v)).ToList();

            var ans = GetAns(n, p);
            IO.Printer.Out.WriteLine(ans);
            IO.Printer.Out.Flush();
        }
        
        public static long GetAns(int n, List<int> p)
        {
            var rightLarger = GetRightLarger(p);
            var leftLarger = GetLeftLarger(p);
            var ret = 0L;

            for (int i = 0; i < p.Count(); i++)
            {
                // left: smaller than p[i], right: one element which is larger than p[i]
                var leftCount = GetSmallerLeftCount(rightLarger, leftLarger, i);
                leftCount++;    // add itself
                var rightCount = GetLargerRightCount(p, rightLarger, leftLarger, i);
                ret += (long)leftCount * rightCount * p[i];

                // right: smaller than p[i], left: one element which is larger than p[i]
                leftCount = GetLargerLeftCount(p, rightLarger, leftLarger, i);
                rightCount = GetSmallerRightCount(rightLarger, leftLarger, i);
                rightCount++;   // add itself
                ret += (long)leftCount * rightCount * p[i];
            }

            return ret;
        }

        public static List<int> GetRightLarger(List<int> p)
        {
            var ret = Enumerable.Range(0, p.Count()).Select(v => -1).ToList();
            var que = new PriorityQueue<Node>();

            for (int i = 0; i < p.Count(); i++)
            {
                while(que.Count() > 0 && que.Peek().Val < p[i])
                {
                    var n = que.Pop();
                    ret[n.Idx] = i;
                }
                que.Push(new Node(p[i], i));
            }

            return ret;
        }

        public static List<int> GetLeftLarger(List<int> p)
        {
            var ret = Enumerable.Range(0, p.Count()).Select(v => -1).ToList();
            var que = new PriorityQueue<Node>();

            for (int i = p.Count() - 1; i >= 0; i--)
            {
                while (que.Count() > 0 && que.Peek().Val < p[i])
                {
                    var n = que.Pop();
                    ret[n.Idx] = i;
                }
                que.Push(new Node(p[i], i));
            }

            return ret;
        }

        public static int GetSmallerRightCount(List<int> right, List<int> left, int idx)
        {
            var largeIdx = right[idx];
            largeIdx--;
            return Math.Max(0, largeIdx - idx);
        }

        public static int GetSmallerLeftCount(List<int> right, List<int> left, int idx)
        {
            var largeIdx = left[idx];
            largeIdx++;
            return Math.Max(0, idx - largeIdx);
        }

        public static int GetLargerRightCount(List<int> p, List<int> right, List<int> left, int idx)
        {
            var largeIdx = right[idx];
            if (largeIdx == -1) return 0;
            var largeIdx2 = largeIdx + 1;
            while (largeIdx2 < p.Count() && p[largeIdx2] < p[idx]) largeIdx2++;

            return largeIdx2 - largeIdx;
        }

        public static int GetLargerLeftCount(List<int> p, List<int> right, List<int> left, int idx)
        {
            var largeIdx = left[idx];
            if (largeIdx == -1) return 0;
            var largeIdx2 = largeIdx - 1;
            while (largeIdx2 >= 0 && p[largeIdx2] < p[idx]) largeIdx2--;

            return largeIdx - largeIdx2;
        }
    }

    public class Node : IComparable
    {
        public int Val;
        public int Idx;

        public Node(int val, int idx)
        {
            Val = val;
            Idx = idx;
        }

        public int CompareTo(object obj)
        {
            var oth = obj as Node;
            return this.Val.CompareTo(oth.Val);
        }
    }

    public class PriorityQueue<T> where T : IComparable
    {
        private IComparer<T> _comparer = null;
        private int _type = 0;

        private T[] _heap;
        private int _sz = 0;

        private int _count = 0;

        /// <summary>
        /// Priority Queue with custom comparer
        /// </summary>
        public PriorityQueue(IComparer<T> comparer)
        {
            _heap = new T[128];
            _comparer = comparer;
        }

        /// <summary>
        /// Priority queue
        /// </summary>
        /// <param name="type">0: asc, 1:desc</param>
        public PriorityQueue(int type = 0)
        {
            _heap = new T[128];
            _type = type;
        }

        private int Compare(T x, T y)
        {
            if (_comparer != null) return _comparer.Compare(x, y);
            return _type == 0 ? x.CompareTo(y) : y.CompareTo(x);
        }

        public void Push(T x)
        {
            _count++;
            if (_count > _heap.Length)
            {
                var newheap = new T[_heap.Length * 2];
                for (int n = 0; n < _heap.Length; n++) newheap[n] = _heap[n];
                _heap = newheap;
            }

            //node number
            var i = _sz++;

            while (i > 0)
            {
                //parent node number
                var p = (i - 1) / 2;

                if (Compare(_heap[p], x) <= 0) break;

                _heap[i] = _heap[p];
                i = p;
            }

            _heap[i] = x;
        }

        public T Pop()
        {
            _count--;

            T ret = _heap[0];
            T x = _heap[--_sz];

            int i = 0;
            while (i * 2 + 1 < _sz)
            {
                //children
                int a = i * 2 + 1;
                int b = i * 2 + 2;

                if (b < _sz && Compare(_heap[b], _heap[a]) < 0) a = b;

                if (Compare(_heap[a], x) >= 0) break;

                _heap[i] = _heap[a];
                i = a;
            }

            _heap[i] = x;

            return ret;
        }

        public int Count()
        {
            return _count;
        }

        public T Peek()
        {
            return _heap[0];
        }

        public bool Contains(T x)
        {
            for (int i = 0; i < _sz; i++) if (x.Equals(_heap[i])) return true;
            return false;
        }

        public void Clear()
        {
            while (this.Count() > 0) this.Pop();
        }

        public IEnumerator<T> GetEnumerator()
        {
            var ret = new List<T>();

            while (this.Count() > 0)
            {
                ret.Add(this.Pop());
            }

            foreach (var r in ret)
            {
                this.Push(r);
                yield return r;
            }
        }

        public T[] ToArray()
        {
            T[] array = new T[_sz];
            int i = 0;

            foreach (var r in this)
            {
                array[i++] = r;
            }

            return array;
        }
    }

#if DEBUG

    [TestClass]
    public class Test
    {
        [TestMethod]
        public void GetSmallerRightCount()
        {
            var p = new List<int> { 2, 5, 1, 3, 4, 7, 6 };
            var right = Program.GetRightLarger(p);
            var left = Program.GetLeftLarger(p);
            var idx = 3;
            var exp = 0;
            var ans = Program.GetSmallerRightCount(right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 1;
            exp = 3;
            ans = Program.GetSmallerRightCount(right, left, idx);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void GetSmallerLeftCount()
        {
            var p = new List<int> { 2, 5, 1, 3, 4, 7, 6 };
            var right = Program.GetRightLarger(p);
            var left = Program.GetLeftLarger(p);
            var idx = 3;
            var exp = 1;
            var ans = Program.GetSmallerLeftCount(right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 4;
            exp = 2;
            ans = Program.GetSmallerLeftCount(right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 6;
            exp = 0;
            ans = Program.GetSmallerLeftCount(right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 0;
            exp = 0;
            ans = Program.GetSmallerLeftCount(right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 1;
            exp = 1;
            ans = Program.GetSmallerLeftCount(right, left, idx);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void GetLargerRightCount()
        {
            var p = new List<int> { 2, 5, 1, 3, 4, 7, 6 };
            var right = Program.GetRightLarger(p);
            var left = Program.GetLeftLarger(p);
            var idx = 2;
            var exp = 1;
            var ans = Program.GetLargerRightCount(p, right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 4;
            exp = 1;
            ans = Program.GetLargerRightCount(p, right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 1;
            exp = 1;
            ans = Program.GetLargerRightCount(p, right, left, idx);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void GetLargerLeftCount()
        {
            var p = new List<int> { 2, 5, 1, 3, 4, 7, 6 };
            var right = Program.GetRightLarger(p);
            var left = Program.GetLeftLarger(p);
            var idx = 2;
            var exp = 1;
            var ans = Program.GetLargerLeftCount(p, right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 3;
            exp = 2;
            ans = Program.GetLargerLeftCount(p, right, left, idx);
            Assert.AreEqual(exp, ans);

            idx = 6;
            exp = 6;
            ans = Program.GetLargerLeftCount(p, right, left, idx);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void GetRightLarger()
        {
            var p = new List<int> { 2, 5, 1, 3, 4, 7, 6 };
            var exp = new List<int> { 1, 5, 3, 4, 5, -1, -1 };
            var ans = Program.GetRightLarger(p);
            Assert.IsTrue(IsEq(exp, ans));
        }

        [TestMethod]
        public void GetLeftLarger()
        {
            var p = new List<int> { 2, 5, 1, 3, 4, 7, 6 };
            var exp = new List<int> { -1, -1, 1, 1, 1, -1, 5 };
            var ans = Program.GetLeftLarger(p);
            Assert.IsTrue(IsEq(exp, ans));
        }

        [TestMethod]
        public void Test1()
        {
            var n = 3;
            var p = new List<int> { 2, 3, 1 };
            var exp = 5L;
            var ans = Program.GetAns(n, p);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void Test2()
        {
            var n = 5;
            var p = new List<int> { 1, 2, 3, 4, 5 };
            var exp = 30L;
            var ans = Program.GetAns(n, p);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void Test3()
        {
            var n = 8;
            var p = new List<int> { 8, 2, 7, 3, 4, 5, 6, 1 };
            var exp = 136L;
            var ans = Program.GetAns(n, p);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void Test4()
        {
            var n = 2;
            var p = new List<int> { 1, 2 };
            var exp = 1L;
            var ans = Program.GetAns(n, p);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void Test5()
        {
            var n = 3;
            var p = new List<int> { 1, 2, 3 };
            var exp = 5L;
            var ans = Program.GetAns(n, p);
            Assert.AreEqual(exp, ans);
        }

        [TestMethod]
        public void Test6()
        {
            var n = 3;
            var p = new List<int> { 3, 2, 1 };

            // (0, 1) => 2
            // (0, 2) => 2
            // (1, 2) => 1

            var exp = 5L;
            var ans = Program.GetAns(n, p);
            Assert.AreEqual(exp, ans);
        }

        public bool IsEq<T>(List<T> l1, List<T> l2)
        {
            if (l1.Count() != l2.Count()) return false;
            for (int i = 0; i < l1.Count(); i++)
            {
                if (!l1[i].Equals(l2[i])) return false;
            }
            return true;
        }

    }
#endif
}

namespace IO
{
    using System.IO;
    using System.Text;
    using System.Globalization;

    public class Printer : StreamWriter
    {
        static Printer()
        {
            Out = new Printer(Console.OpenStandardOutput()) { AutoFlush = false };
        }

        public static Printer Out { get; set; }

        public override IFormatProvider FormatProvider
        {
            get { return CultureInfo.InvariantCulture; }
        }

        public Printer(Stream stream)
            : base(stream, new UTF8Encoding(false, true))
        {
        }

        public Printer(Stream stream, Encoding encoding)
            : base(stream, encoding)
        {
        }

        public void Write<T>(string format, T[] source)
        {
            base.Write(format, source.OfType<object>().ToArray());
        }

        public void WriteLine<T>(string format, T[] source)
        {
            base.WriteLine(format, source.OfType<object>().ToArray());
        }
    }

    public class StreamScanner
    {
        public StreamScanner(Stream stream)
        {
            str = stream;
        }

        public readonly Stream str;
        private readonly byte[] buf = new byte[1024];
        private int len, ptr;
        public bool isEof;

        public bool IsEndOfStream
        {
            get { return isEof; }
        }

        private byte read()
        {
            if (isEof) return 0;
            if (ptr < len) return buf[ptr++];
            ptr = 0;
            if ((len = str.Read(buf, 0, 1024)) > 0) return buf[ptr++];
            isEof = true;
            return 0;
        }

        public char Char()
        {
            byte b;
            do b = read(); while ((b < 33 || 126 < b) && !isEof);
            return (char)b;
        }

        public string Scan()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b >= 33 && b <= 126; b = (char)read())
                sb.Append(b);
            return sb.ToString();
        }

        public string ScanLine()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b != '\n'; b = (char)read())
                if (b == 0) break;
                else if (b != '\r') sb.Append(b);
            return sb.ToString();
        }

        public long Long()
        {
            if (isEof) return long.MinValue;
            long ret = 0;
            byte b;
            var ng = false;
            do b = read(); while (b != 0 && b != '-' && (b < '0' || '9' < b));
            if (b == 0) return long.MinValue;
            if (b == '-')
            {
                ng = true;
                b = read();
            }
            for (; ; b = read())
            {
                if (b < '0' || '9' < b)
                    return ng ? -ret : ret;
                ret = ret * 10 + b - '0';
            }
        }

        public int Integer()
        {
            return (isEof) ? int.MinValue : (int)Long();
        }

        public double Double()
        {
            var s = Scan();
            return s != "" ? double.Parse(s, CultureInfo.InvariantCulture) : double.NaN;
        }

        static T[] enumerate<T>(int n, Func<T> f)
        {
            var a = new T[n];
            for (int i = 0; i < n; ++i) a[i] = f();
            return a;
        }

        public char[] Char(int n)
        {
            return enumerate(n, Char);
        }

        public string[] Scan(int n)
        {
            return enumerate(n, Scan);
        }

        public double[] Double(int n)
        {
            return enumerate(n, Double);
        }

        public int[] Integer(int n)
        {
            return enumerate(n, Integer);
        }

        public long[] Long(int n)
        {
            return enumerate(n, Long);
        }
    }
}