Problem:
Score : 400 points

Problem Statement

One day, Snuke was given a permutation of length N, a_1, a_2, ..., a_N, from his friend.

Find the following:

Constraints

1 ≦ N ≦ 200,000

(a_1, a_2, ..., a_N) is a permutation of (1, 2, ..., N).

Input

The input is given from Standard Input in the following format:

N
a_1 a_2 ... a_N

Output

Print the answer.

Note that the answer may not fit into a 32-bit integer.

Sample Input 1

3
2 1 3

Sample Output 1

9

Sample Input 2

4
1 3 2 4

Sample Output 2

19

Sample Input 3

8
5 4 8 1 2 6 7 3

Sample Output 3

85

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author anand.oza
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        BMinimumSum solver = new BMinimumSum();
        solver.solve(1, in, out);
        out.close();
    }

    static class BMinimumSum {
        IntSegmentTree min;
        int n;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            n = in.nextInt();

            min = new IntSegmentTree(n, Math::min, Integer.MAX_VALUE);
            for (int i = 0; i < n; i++) {
                int a = in.nextInt();
                min.value[n + i] = a;
            }

            min.rebuild();

            long answer = 0;
            int currentValue;
            for (int i = 0; i < n; i++) {
                currentValue = min.get(i);

                int l = i - (binarySearchLeft(i, currentValue) - 1);

                int r = i + (binarySearchRight(i, currentValue) - 1);

                answer += currentValue * (nc2(r - l + 2) - nc2(i - 1 - l + 2) - nc2(r - (i + 1) + 2));
            }

            out.println(answer);
        }

        public int binarySearchLeft(int currentIndex, int currentValue) {
            int tooSmall = 0, tooBig;
            if (tooManyOnLeft(currentIndex, currentValue, tooSmall)) {
                return tooSmall;
            }

            for (tooBig = 1; !tooManyOnLeft(currentIndex, currentValue, tooBig); tooBig *= 2) ;

            if (!tooManyOnLeft(currentIndex, currentValue, tooBig - 1)) {
                return tooBig;
            }

            while (tooBig - tooSmall > 1) {
                int center = (tooBig + tooSmall) / 2;
                if (!tooManyOnLeft(currentIndex, currentValue, center)) {
                    tooSmall = center;
                } else {
                    tooBig = center;
                }
            }

            return tooBig;
        }

        public int binarySearchRight(int currentIndex, int currentValue) {
            int tooSmall = 0, tooBig;
            if (tooManyOnRight(currentIndex, currentValue, tooSmall)) {
                return tooSmall;
            }

            for (tooBig = 1; !tooManyOnRight(currentIndex, currentValue, tooBig); tooBig *= 2) ;

            if (!tooManyOnRight(currentIndex, currentValue, tooBig - 1)) {
                return tooBig;
            }

            while (tooBig - tooSmall > 1) {
                int center = (tooBig + tooSmall) / 2;
                if (!tooManyOnRight(currentIndex, currentValue, center)) {
                    tooSmall = center;
                } else {
                    tooBig = center;
                }
            }

            return tooBig;
        }

        private boolean tooManyOnLeft(int currentIndex, int currentValue, int elementCount) {
            if (elementCount <= 0) {
                return false;
            }

            if (currentIndex - elementCount < 0) {
                return true;
            }

            return min.query(currentIndex - elementCount, currentIndex - 1) < currentValue;
        }

        private boolean tooManyOnRight(int currentIndex, int currentValue, int elementCount) {
            if (elementCount <= 0) {
                return false;
            }

            if (currentIndex + elementCount >= n) {
                return true;
            }

            return min.query(currentIndex + 1, currentIndex + elementCount) < currentValue;
        }

        static long nc2(long n) {
            if (n < 2) return 0;
            return n * (n - 1) / 2;
        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }

    static class IntSegmentTree {
        public int size;
        public int[] value;
        private final IntSegmentTree.Combiner combiner;
        private final int identityElement;

        public IntSegmentTree(int size, IntSegmentTree.Combiner combiner, int identityElement) {
            this.size = size;
            value = new int[2 * size];
            Arrays.fill(value, identityElement);
            this.combiner = combiner;
            this.identityElement = identityElement;
        }

        private int combine(int a, int b) {
            return combiner.combine(a, b);
        }

        public void rebuild() {
            for (int i = size - 1; i > 0; i--) {
                value[i] = combine(value[2 * i], value[2 * i + 1]);
            }
        }

        public int get(int i) {
            return value[size + i];
        }

        public int query(int i, int j) {
            int res_left = identityElement, res_right = identityElement;
            for (i += size, j += size; i <= j; i /= 2, j /= 2) {
                if ((i & 1) == 1) res_left = combine(res_left, value[i++]);
                if ((j & 1) == 0) res_right = combine(value[j--], res_right);
            }
            return combine(res_left, res_right);
        }

        public interface Combiner {
            int combine(int a, int b);

        }

    }
}