I hate Ping Pong!
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2492
题意:
有一坨人排成一条直线,每个人都有一个技能等级,有天他们想互相比试一下,a与b比试,c做裁判,规则如下:
1.c的位置必须在a、b之间;
2.c的技能等级必须在a、b之间。
思路:
以每个裁判为单位,可推出公式:裁判左边技能等级小于他的人数 * 裁判右边技能等级大于他的人数 = 该裁判所进行的比赛次数
所以可以通过两次树状数组,一次从左插入,一次从右插入来得出答案。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define lowbit(x) x & (-x)
const int M = 20020;
const int S = 100020;
int tree[S], n, v[M], leftlower[M], leftupper[M], rightlower[M], rightupper[M];
void add(int a)
{
while(a <= S)
{
tree[a]++;
a += lowbit(a);
}
}
int sum(int a)
{
int total = 0;
while(a > 0)
{
total += tree[a];
a -= lowbit(a);
}
return total;
}
main()
{
int T;
cin >> T;
while(T--)
{
cin >> n;
for(int i = 1; i <= n; i++)
scanf("%d", &v[i]);
memset(tree, 0, sizeof(tree));
for(int i = 1; i <= n; i++)
{
add(v[i]);
leftlower[i] = sum(v[i] - 1);
leftupper[i] = sum(S - 1) - sum(v[i]);
}
memset(tree, 0, sizeof(tree));
for(int i = n; i >= 1; i--)
{
add(v[i]);
rightlower[i] = sum(v[i] - 1);
rightupper[i] = sum(S - 1) - sum(v[i]);
}
long long res = 0;
for(int i = 1; i <= n; i++)
res += (long long)rightlower[i] * leftupper[i] + (long long)rightupper[i] * leftlower[i];
cout << res << endl;
}
}