树状数组的getsum函数功能是判断左边比他小的个数,而i-1-getsum(x)是找右边比他小的,等于的话是i-getsum(x),惊人的发现,哈哈,排好序了吗,一开始是最大的,最后会形成一个序列,需要的步数就是最小的步数实现序列逆序对数,这个好像是一个结论,我也不是太懂,但是我觉得可以直接使用,也就是一个序列最小实现一个高峰序列的话,也就是求逆序对数最小可以形成的次数,注意相等的情况需要特判!
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 300005;
ll ans;
int n,l,r;
struct node{
int v,p;
}t[maxn];
int tr[maxn];
int cmp(node a,node b){
return a.v>b.v;
}
int lowbit(int x){
return x&(-x);
}
int add(int x){
while(x<=n){
tr[x]++;
x+=lowbit(x);
}
}
int query(int x){
int res=0;
while(x>0){
res+=tr[x];
x-=lowbit(x);
}
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&t[i].v);
t[i].p=i;
}
sort(t+1,t+n+1,cmp);
// for(int i=1;i<=n;i++){
// cout<<t[i].v<<" "<<t[i].p<<endl;
// }
for(int i=1;i<=n;i++){
int tp=i;
while(t[tp].v==t[tp+1].v&&tp<n)tp++;
for(int j=i;j<=tp;j++){
ans+=min(query(t[j].p),i-1-query(t[j].p));
}
for(int j=i;j<=tp;j++){
add(t[j].p);
}
i=tp;
}
cout<<(ll)ans<<endl;
return 0;
}