题目
题解思路
这一步想了一个小时才想明白 。
因为数组只包含了N的排序数。
所以我们可以这样操作。
从左到右
将 数组的数 Y 标记(即自增1)进树状数组。
利用树状数组logn求前缀和的特性来判断 大于Y的数有几个 小于Y的数有几个。(其实这些数都在 Y 的左边 )
同理求出右边的数
相乘就是正反逆序数 。
for (int i = 1 ; i <= n ; i++ )
{
int y = a[i];
gr[i] = sum(n) - sum(y) ;
lo[i] = sum(y-1);
xg( y , 1 );
}
memset( tre , 0 , sizeof(tre) ) ;
long long ans1 = 0 , ans2 = 0 ;
for (int i = n ; i >= 1 ; i-- )
{
int y = a[i];
ans1 += (long long ) gr[i] * ( sum(n) - sum(y) );
ans2 += (long long ) lo[i] * sum(y-1);
xg( y , 1 );
}
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2000010 ;
int a[ N ] , tre[ N ] ;
int lo[ N ] , gr[ N ] ;
int n;
int lbit(int x )
{
return x & ( -x );
}
void xg(int x , int y )
{
for (int i = x ; i <= n ; i += lbit(i) )
tre[i] += y;
}
long long sum(int x )
{
long long ans = 0 ;
for (int i = x ; i ; i -= lbit(i) )
ans += tre[i];
return ans;
}
int main ()
{
ios::sync_with_stdio(false);
cin >> n ;
for (int i = 1 ; i <= n ; i++ )
cin>>a[i];
for (int i = 1 ; i <= n ; i++ )
{
int y = a[i];
gr[i] = sum(n) - sum(y) ;
lo[i] = sum(y-1);
xg( y , 1 );
}
memset( tre , 0 , sizeof(tre) ) ;
long long ans1 = 0 , ans2 = 0 ;
for (int i = n ; i >= 1 ; i-- )
{
int y = a[i];
ans1 += (long long ) gr[i] * ( sum(n) - sum(y) );
ans2 += (long long ) lo[i] * sum(y-1);
xg( y , 1 );
}
cout << ans1 << " "<< ans2 <<"\n";
return 0 ;
}