解题思路
这道题传统做法很明显,暴力枚举,时间复杂度O(n^2).
考虑用树状数组优化到O(nlogn)。我们可以保存下标,再排序一遍,然后从大到小枚举a_i,每次在原下标位置处加1,查询树状数组中下标在a_i之前的,与a_i形成逆序对。
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;
int n,kl[500010],tree[500010];
ll ans;
struct c{
int id,x;
}a[500010];
bool cmp(c l,c r)
{
if(l.x==r.x)return l.id>r.id;
return l.x>r.x;
}
void add(int x,int y)
{
for(int i=x;i<=n;i+=i&(-i))
tree[i]+=y;
}
ll sum(int x)
{
ll ans=0;
for(int i=x;i;i-=i&(-i))
ans+=tree[i];
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
add(a[i].id,1);
ans+=sum(a[i].id-1);
}
printf("%lld",ans);
}