题目:
给出一个数组,求其逆序对个数,逆序对即i<j&&a[i]>a[j]的对数!!
思路:
因为a[i]数比较大,且本题与a[i]本身大小无关,仅与元素直接差值有关,故先用离散化减少空间,然后将数组降序排序后表示每个元素出现的位置,然后用树状数组求和,有效且大大降低了时间复杂度!排序后a[i]数组是降序的,c[i]表示对应每个元素原本的位置,从前往后枚举一遍,每个数为后面比自己晚出现&&比自己小 (在后面了,说明肯定比它小) 贡献1;
例子:
原本a[i]:5 7 2 5 2
a[i]:7 5 5 2 2
c[i]:2 4 1 5 3
代码如下:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll n;
ll a[500005],c[500005],cnt[500005];
void add(ll x,ll k)
{
for(ll i=x;i<=n;i+=i&-i)
{
cnt[i]+=k;
}
}
ll query(ll x)
{
ll sum=0;
for(ll i=x;i;i-=i&-i)
{
sum+=cnt[i];
}
return sum;
}
ll cmp(ll x,ll y)
{
if(a[x]==a[y]) return x>y;
else return a[x]>a[y];//相同数字后出现在前面
}
void solve()
{
cin>>n;
ll ans=0;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
c[i]=i;
}
sort(c+1,c+1+n,cmp);
//5 7 2 5 2
//变为
//2 4 1 5 3
//2为4,5,3贡献1,4为5贡献1,1为5,3贡献1,5不贡献,3不贡献
//和为6
for(ll i=1;i<=n;i++)
{
add(c[i],1);
ans+=query(c[i]-1);
//add(c[i],1);顺序都可以
}
/*树状数组作用:
用来求和运算,避免TLE
*/
cout<<ans<<'\n';
}
//-----------------------------------------------------------------------------------------
int main()
{
//ll t = 1 ;
//cin >> t ;
//for(ll i = 1 ; i <= t ; i++){
// cout << "Case #" << i << ": ";
solve();
//cout<<'\n';
//}
}