Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

The Number of Inversions

For a given sequence $A = \{a_0, a_1, ... a_{n-1}\}$, the number of pairs $(i, j)$ where $a_i > a_j$ and $i < j$, is called the number of inversions. The number of inversions is equal to the number of swaps of Bubble Sort defined in the following program:

bubbleSort(A)
cnt = 0 // the number of inversions
for i = 0 to A.length-1
for j = A.length-1 downto i+1
if A[j] < A[j-1]
swap(A[j], A[j-1])
cnt++

return cnt

For the given sequence $A$, print the number of inversions of $A$. Note that you should not use the above program, which brings Time Limit Exceeded.

Input

In the first line, an integer $n$, the number of elements in $A$, is given. In the second line, the elements $a_i$ ($i = 0, 1, .. n-1$) are given separated by space characters.

output

Print the number of inversions in a line.

Constraints

$ 1 \leq n \leq 200,000$

$ 0 \leq a_i \leq 10^9$

$a_i$ are all different

Sample Input 1

5
3 5 2 1 4

Sample Output 1

6

Sample Input 2

3
3 1 2

Sample Output 2

2

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{
	/*

・概要
	「数列の『初めの』要素からi番目までの区間和」を求めるために使用。
	（SegmentTreeを簡略化・特殊化したものとも。）

	以下の2つのクエリに対し、ともにO(logN)で応答可能。
	1. 区間和を求める（GetSum()）
	2. 特定の要素に加算する（AddTo()）

	cf.後に要素に加算することがない場合には、単純に累積和を計算しておけば良い。

	cf. 「はじめの要素からi番目まで」ではなく、「left ~ right間の和」を求める場合
	　→SegmentTreeを使った方が良いが、BITでも実現可能

・使用法
	1. BinaryIndexedTreeクラスのオブジェクトを作成（引数は要素数）
	（e.g. BinaryIndexedTree bit = new BinaryIndexedTree(N);）

	2. 配列の初期化（元の配列を渡す）（計算量はO(N * logN)）
	（e.g. bit.Initialize(arr);）

	3. 適宜、クエリに回答（計算量はO(logN)）
		a. AddToメソッドで、i番目の要素に加算
		（e.g. bit.AddTo(idx, value);）

		b. GetSumメソッドで、区間 left ~ rightまでの合計値を取得（閉区間）
		（e.g. long res = bit.GetSum(left, right);）

	4. 転倒数を求める場合、初期化した後でInversionNum()メソッドを使う。（計算量はO(N * logN)）
	（cf. AddToをしていた場合、加算後の状態での転倒数が求まる。）
	(e.g. long ans = bit.InversionNum();)
	（※転倒数は、バブルソートの交換回数と等しい。順序がひっくり返ってるペア数のこと。）

	*/

	//Main
	static void Main(string[] args)
	{
		//要素数
		int N = int.Parse(Console.ReadLine());
		//元の配列
		long[] arr = Console.ReadLine().Split(' ').Select(i => long.Parse(i)).ToArray();

		//1. BinaryIndexedTreeクラスのオブジェクトを作成
		BinaryIndexedTree bit = new BinaryIndexedTree(N);

		//2. 配列の初期化（元の配列を渡す）
		bit.Initialize(arr);

		/*
		//3.入力に応じて、更新 or 回答を行う
		//クエリ数を読み込む
		int Q = int.Parse(Console.ReadLine());
		for(int i=0; i<Q; i++){
			//読み込む
			string[] S1 = Console.ReadLine().Split(' ');
			//クエリの種類
			int com = int.Parse(S1[0]);
			//数値
			int x = int.Parse(S1[1]);
			int y = int.Parse(S1[2]);

			//加算クエリの場合
			if(com == 0){
				//インデックスxに、yを加算
				bit.AddTo(x,y);
			}
			//回答クエリの場合
			else{
				//閉区間[x,y]の合計値を取得
				long res = bit.GetSum(x,y);
				//出力
				Console.WriteLine(res);
			}
		}
		*/

		//4. 転倒数を求める
		long ans = bit.InversionNum();
		Console.WriteLine(ans);

		//cf. debug用の、完全二分木出力メソッド
		//bit.DebugWrite();
	}
}


//BinaryIndexedTreeのクラス
/*
	long型とする。
*/
class BinaryIndexedTree
{
	//元の配列
	private long[] originalArr;
	//BITの配列
	/*
	元の配列を1-indexedに直して実装しているので注意。
	*/
	private long[] tree;
	//配列の要素数（元の配列の要素数+1となる）
	private int length;

	//コンストラクタ
	/*
	引数は要素数
	*/
	public BinaryIndexedTree(int len){
		//要素数は元の要素数+1となる
		this.length = len + 1;

		//元の配列を初期化
		this.originalArr = new long[len];
		//treeの初期化
		this.tree = new long[this.length];
	}

	//元の配列に合わせ、BITを初期化するメソッド
	/*
	初期化にO(N * lonN)かかるので注意
	*/
	public void Initialize(long[] arr){
		for(int i=0; i<arr.Length; i++){
			this.AddTo(i, arr[i]);
		}
	}

	//要素に加算するメソッド
	/*
	引数は、加算対象のインデックスと、加える値
	*/
	public void AddTo(int idx, long val){
		//元の配列を更新
		this.originalArr[idx] += val;

		//1-indexedに直していることを反映
		idx ++;

		//cf. i & -iにより、iの立っているビットのうち最下位のものが求まる。
		for(int i=idx; i<this.length; i+=(i & -i)){
			this.tree[i] += val;
		}
	}

	//区間和を計算するメソッド
	/*
	引数は区間。
	閉区間[left, right]の合計値を吐き出す。
	*/
	public long GetSum(int left, int right){
		//1-indexedに直していることを反映
		left ++;
		right ++;

		return this.Sum(right) - this.Sum(left-1);
	}

	//インデックス0からi番目までの合計値を計算
	/*
	実装の上では、1-indexedに書き直しているので注意
	*/
	private long Sum(int right){
		if(right < 1){
			return 0;
		}
		else{
			long res = 0;
			for(int i=right; i>0; i-=(i & -i)){
				res += this.tree[i];
			}
			return res;
		}
	}

	//現在の配列の状態に対して、転倒数を計算するメソッド
	public long InversionNum(){
		//転倒数計算用のBIT
		BinaryIndexedTree bit2 = new BinaryIndexedTree(this.length-1);

		//元の配列をソート
		long[] sorted = new long[this.length-1];
		Array.Copy(this.originalArr, sorted, this.length-1);
		Array.Sort(sorted);

		//転倒数を求める
		long res = 0;
		for(int i=0; i<this.length-1; i++){
			int idx = Array.BinarySearch(sorted,originalArr[i]);
			res += (i - bit2.GetSum(0,idx));
			bit2.AddTo(idx,1);
		}

		return res;
	}

	//debug用の、完全二分木出力メソッド
	public void DebugWrite(){
		for(int i=0; i<this.length; i++){
			Console.Write("t[{0}]={1},",i,this.tree[i]);
		}
	}
}