首页 > 代码库 > TreeArray_hoj2275
TreeArray_hoj2275
我们对于每一个数字,记录他之前比他小的数的个数,他之后,比他小的数的个数,然后乘积就是这个数字为中间元素的 所求序列的个数,求和就是所有的了。
用两个树状数组,或者用两次。
#include <cstdio>
#include <cstring>
const int M = 50009;
int d[M], c[M], a[M], b[M], n;
inline int lowbit(int i) {
return i & (-i);
}
void Modify(int i, int m) {
while ( i <= 32768 ) {
c[i] += m;
i += lowbit(i);
}
}
int Sum(int i) {
int ret = 0;
while ( i > 0 ) {
ret += c[i];
i -= lowbit(i);
}
return ret;
}
int main () {
int i, j;
long long ans;
while ( scanf("%d", &n) != EOF ) {
memset(c, 0, sizeof(c) );
for ( i = 0; i < n; i++ ) {
scanf("%d", &d[i]);
a[i] = Sum( d[i] );
/////////////////////////////////////////////////////////////////////////////////////////////////////
对于得到的d[i]序列,比如为5 9 1 8,将这些数字本身当做树状数组的编号。即重新按照大小顺序重新排列了一下,即树状数组是这样的:c[x] 表示大小为x的数是否存在
(这里也可以考虑一下离散化一下) 同时i遍历的顺序是从小变大,保证sum求和的时候求的都是前面的,而不是后面的。这样才能保证树状数组sum(x)统计前面的数字都是比它小的数。大小为d[x]的数字加进来之后,d[x]+1以及后面的数字,比他们小的、在他们之前的数字又多了一个
/////////////////////////////////////////////////////////////////////////////////////////////////////
Modify( d[i] + 1, 1 );
}
memset(c, 0, sizeof(c) );
//树状数组清空,从后向前
for ( i = n - 1; i >= 0; i-- ) {
b[i] = Sum(d[i]);
Modify(d[i] + 1, 1 );
}
// for ( i = 0; i < n; i++ ) {
// printf("%d ", a[i]);
// }
// printf("\n");
// for ( i = 0; i < n; i++ ) {
// printf("%d ", b[i]);
// }
// printf("\n\n");
ans = 0;
for ( i = 0; i < n; i++ )
ans += (long long)a[i] * (long long)b[i];
printf("%lld\n", ans);
}
}
/*
5
1 1 1 1 1
5
0 2 0 2 0
*/
TreeArray_hoj2275