题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2492
题目大意:求有多少组数满足:( i < j < k 并且 ai < aj < ak) ||( i > j > k 并且 ai < aj < ak)
算法:线段树
思路:presm[i] = 前面有多少个数字比a[i]小,endbig[i]后面有多少个数字比a[i]大;prebig[i] = 前面有多少个数字比a[i]大,endsm[i]后面有多少个数字比a[i]小;公式: sum = ∑(presm[i] * endbig[i]+prebig[i] * endsm[i])(1 < i < n)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m = (l+r) >> 1
const int Max = 100000;
int a[565656];
int w[898989];
int cnt[498989];
void update(int d, int l, int r, int rt)
{
cnt[rt] ++;
if(l == r)
return ;
mid ;
if(d <= m)
update(d, lson);
else
update(d, rson);
}
int query(int k, int l, int r, int rt)
{
if(l == r)
return cnt[rt];
mid ;
if(k <= m)
return query(k, lson);
else{
int ret = query(k, rson);
return ret + cnt[rt << 1];
}
}
int bin(int key, int n)
{
int l = 1, r = n;
while(l <= r)
{
mid ;
if(key == w[m])
return m;
if(key < w[m])
r = m-1;
else
l = m+1;
}
return -1;
}
int main()
{
int n, T;
scanf("%d", &T);
while(T -- )
{
scanf("%d", &n);
__int64 ans = 0;
memset(cnt, 0, sizeof(cnt));
int i;
for(i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
w[i] = a[i];
}
sort(w+1, w+n+1);
for(i = 1; i <= n; i ++)
{
int xx = bin(a[i], n);
int k = query(a[i], 1, Max, 1);//pre比他小的
int m = xx - 1 - k;//后面比他小的
int u = (n-i) - m;//后面比他大的
int v = i - 1 - k;//前面比他大的
update(a[i], 1, Max, 1);
ans += (__int64)k * (__int64)u + (__int64)v * (__int64)m;
}
printf("%I64d\n", ans);
}
return 0;
}