题目:
每两人比赛需要裁判(第三名比赛队员充当),并且裁判的等级在两者之间,并且裁判需要在那两名选手的位置之间,问可以安排多少场这样的比赛。
分析:
树状数组枚举裁判,分别求到左边位置比该队员的等级高的和等级低的选手数目,当求完之后再从左到右分别删除该项后,求到比他等级高的和等级小的,删除操作只需要modify操作时减掉1即可实现。然后根据乘法原理可知用左边的等级高的*右边等级低的+右边等级高的*左边等级低的。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int X = 100005;
int n,a[X];
long long r[X],l[X];
long long r_max[X],l_max[X];
long long c[X];
int lowbit(int x)
{
return x & -x;
}
void modify(int x,int num)
{
while(x<X)
{
c[x] += num;
x += lowbit(x);
}
}
long long query(int x)
{
long long ans = 0;
while(x>0)
{
ans += c[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
memset(c,0,sizeof(c));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
l[i] = query(a[i]);
l_max[i] = query(X-1)-l[i];
modify(a[i],1);
}
for(int i=1;i<=n;i++)
{
modify(a[i],-1);
r[i] = query(a[i]);
r_max[i] = query(X-1)-r[i];
}
long long ans = 0;
for(int i=1;i<=n;i++)
ans += l[i]*r_max[i]+r[i]*l_max[i];
cout<<ans<<endl;
}
return 0;
}