1、知识点:逆序数
2、思路:求中间节点arr[i]前面比它大的数left_big_num[i],后面比它小的数right_small_num[i],答案就是对left_big_num[i]*right_small_num[i]求和, i从2到n-1。用树状数组计算left_big_num[i],right_small_num[i]可以用一个小技巧间接求得,没必要重复计算。看了网上几篇博文,发现有人用排序离散化,其实由于本题n<10^5,可以不用。
/*用途:
**说明:
**算法:
*/
#define LOCAL
#include <cstdio>
#include <string.h>
using namespace std;
#define MAXN 100000+10
typedef long long LL;
int N;
int arr[MAXN];
int tree_arr[MAXN];
LL left_big_num[MAXN];
LL right_small_num[MAXN];
int low_bit(int a);
int get_sum(int ind);
void insert(int ind, int val);
int main()
{
#ifdef LOCAL
freopen("1009_Triple_Inversions.in", "r", stdin);
freopen("1009_Triple_Inversions.out", "w", stdout);
#endif
scanf("%d", &N);
for(int i=1; i<=N; i++)
scanf("%d", &(arr[i]));
if(N < 3){
printf("0");
return 0;
}
for(int i=1; i<=N; i++){
int ls = get_sum(arr[i]);//出现在arr[i]前面且比arr[i]小的数的个数
left_big_num[i] = i-1 - ls;//arr[i]前面出现的所有数的个数减去ls(因为在树状数组中,比arr[i]大的数都插到的arr[i]后面了)
right_small_num[i] = arr[i]-1-ls;//总共比arr[i]小的数减去左边比它小的数
insert(arr[i], 1);//以arr[i]的值为下标插入
}
LL ans = 0;
for(int i=2; i<=N-1; i++)
ans += left_big_num[i] * right_small_num[i];
printf("%lld", ans);
return 0;
}
inline int low_bit(int a)
{
return a&(-a);
}
inline int get_sum(int ind)
{
int sum=0;
while(ind){
sum += tree_arr[ind];
ind -= low_bit(ind);
}
return sum;
}
inline void insert(int ind, int val)
{
while(ind <= N){
tree_arr[ind] += val;
ind += low_bit(ind);
}
}