#include<iostream>
#define int long long
using namespace std;
const int N = 5e5 + 10;
// 定义线段树结构体
struct seg_tree{
int tot; // 动态建树时的节点编号计数器
// 定义线段树的节点结构体
struct node{
int l,r; // 该节点所代表区间的左右端点
int sum; // 该节点所代表区间的和
int s[2]; // s[0] 存储左子节点编号,s[1] 存储右子节点编号
}p[N<<2]; // 存储线段树节点的数组,N<<2 相当于 4*N
// 向上更新节点信息,根据左右子节点的和更新当前节点的和
void push_up(int now){
p[now].sum = p[p[now].s[0]].sum + p[p[now].s[1]].sum;
}
// 初始化线段树,调用 build 函数构建线段树
void init(int n){
build(1,n);
}
// 构建线段树,返回当前节点的编号
int build(int l,int r){
tot++; // 节点编号加 1
p[tot].l = l; // 设置当前节点的左端点
p[tot].r = r; // 设置当前节点的右端点
return tot; // 返回当前节点的编号
}
// 单点修改操作,将位置 pos 的值增加 u
void add(int now,int pos,int u){
int l = p[now].l,r = p[now].r; // 获取当前节点的左右端点
int mid = (l+r) >> 1; // 计算区间中点
// 如果当前节点没有左右子节点,构建左右子节点
if(!p[now].s[0]){
p[now].s[0] = build(p[now].l,mid);
p[now].s[1] = build(mid+1,p[now].r);
}
// 如果当前节点是叶子节点,更新该节点的和
if(l == r){
p[now].sum += u;
return ;
}
// 根据 pos 与 mid 的大小关系,递归修改左子树或右子树
if(mid >= pos) add(p[now].s[0],pos,u);
else add(p[now].s[1],pos,u);
// 向上更新节点信息
push_up(now);
}
// 区间查询操作,查询区间 [tl, tr] 的和
int ask(int now,int tl,int tr){
int sum = 0; // 用于存储查询结果
int l = p[now].l,r = p[now].r; // 获取当前节点的左右端点
int mid = (l+r) >> 1; // 计算区间中点
// 如果当前节点没有左右子节点,构建左右子节点
if(!p[now].s[0]){
p[now].s[0] = build(p[now].l,mid);
p[now].s[1] = build(mid+1,p[now].r);
}
// 如果当前节点的区间完全包含在查询区间内,返回该节点的和
if(tl <= l && r <= tr) return p[now].sum;
// 根据查询区间与 mid 的关系,递归查询左子树和右子树
if(mid >= tl) sum += ask(p[now].s[0],tl,tr);
if(mid < tr) sum += ask(p[now].s[1],tl,tr);
return sum; // 返回查询结果
}
}T;
int n,ans=0; // n 表示数组长度,ans 用于存储逆序对的数量
int a[N]; // 存储输入的数组
signed main(){
// 关闭输入输出流的同步,提高输入输出效率
ios::sync_with_stdio(false);
cin >> n; // 输入数组的长度
T.init(1e9); // 初始化线段树,区间范围为 [1, 1e9]
// 循环读取数组元素
for(int i=1;i<=n;++i){
cin >> a[i]; // 输入数组的第 i 个元素
// 查询区间 [a[i], n] 的和,并累加到 ans 中
ans += T.ask(1,a[i],n);
// 将位置 a[i] 的值加 1
T.add(1,a[i],1);
}
cout << ans; // 输出逆序对的数量
return 0;
}