原题
冒泡排序+逆序对,想出考虑计算高于/低于每个身高的人数,利用树状数组进行人数修改
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
int h[N], tr[N];
int n;
int sum[N];
int ans;
int lowbit(int x){
return x & -x;
}
void add(int a, int v){
for(int i = a; i < N; i += lowbit(i)){
tr[i] += v;
}
}
int query(int x){
int rex = 0;
for(int i = x; i ; i -= lowbit(i)){
rex += tr[i];
}
return rex;
}
signed main()
{
cin>>n;
for(int i = 0; i < n; i ++ ) cin>>h[i], h[i] ++ ;//小朋友的身高可能是0,下列存在query(h[i]-1),会造成溢出,所以让所有数据+1
for(int i = 0; i < n; i ++ ){
sum[i] = query(N - 1) - query(h[i]);//找出身高高于这个小朋友h[i]的小朋友的个数
add(h[i], 1);//这个身高的小朋友数量+1
}
memset(tr, 0, sizeof tr);//重新计算身高低于这个小朋友的人数,要把树状数组清空
for(int i = n - 1; i >= 0; i -- ){
sum[i] += query(h[i] - 1);//加上低于这个身高的人数
add(h[i], 1);
}
//sum[i]记录的是比这个小朋友身高高的和低的总和
//对于每一个比他高的/比他低的他都会被交换一次,所以假设有3个比他高的,2个比他低的
//那么他的不高兴次数应该是1+2+3+4+5,因为第i次交换会使小朋友的不高兴程度+i
for(int i = 0; i < n; i ++ ) ans += sum[i] * (sum[i] + 1) / 2;
cout<<ans<<endl;
return 0;
}