树状数组的典型应用, 参看 《算法笔记》 475页
对于有n个数的数组 A(A[1] ~ A[n]), 对于每一个元素,求出序列中,它的左边比它小的数的个数
本题要点:
1、 题目见,《训练指南》 197 页
2、 ans 要用 long long
3、 输入的数组个数最大值为 20000, 每个 a[i] 的最大值为 100000,
代码的 const int MaxN = 100010 //如果 const int MaxN = 20010, runtime error
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define lowbit(i) ((i)&(-i)) // lowbit(x) 表示x的二进制对应的值
const int MaxN = 100010;
int c[MaxN]; //数组a的树状数组, 下标,从1开始的
int d[MaxN]; //数组 b的树状数组
int n, Test;
int a[MaxN];
int a_small[MaxN]; //数组 a_small[i] 表示第i个数,其左边比a[i] 小的元素个数
int b_small[MaxN]; //数组 b_small[i] 表示第i个数,其左边比b[i] 小的元素个数
//getSum()函数, 返回前x个数的和
int getSum(int x, int * A)
{
int sum = 0;
for(int i = x; i > 0; i-= lowbit(i))
{
sum += A[i];
}
return sum;
}
//update()函数,将第x个数加上v
void update(int x, int v, int* A)
{
for(int i = x; i < MaxN; i += lowbit(i))
{
A[i] += v;
}
}
int main()
{
scanf("%d", &Test);
while(Test--)
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
}
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; ++i)
{
update(a[i], 1, c);
a_small[i] = getSum(a[i] - 1, c);
}
memset(d, 0, sizeof(d));
for(int i = n; i >= 1; --i)
{
update(a[i], 1, d);
b_small[i] = getSum(a[i] - 1, d);
}
long long ans = 0;
for(int i = 2; i <= n - 1; ++i)
{
ans += a_small[i] * (n - i - b_small[i]) + (i - a_small[i] - 1) * b_small[i];
}
printf("%lld\n", ans);
}
return 0;
}
/*
1
3 1 2 3
*/
/*
1
*/