题意:
一条大街上住着 n 个乒乓球爱好者,经常组织比赛切磋技术。
每个人都有一个不同的技能值 ai。每场比赛需要 3 个人:两名选手,一名裁判。
他们有一个奇怪的规定,即裁判必须住在两名选手的中间,并且技能值也在两名选手之间。问一共能组织多少种比赛。
我的:
因为n是10^5,所以以中间的值作为裁判,再遍历两端找到比该点大,小的个数,相乘之后相加的话就是(n^2)的复杂度,会超时的。
所以就利用树状数组,因为树状数组的复杂度是logn,所以总的复杂度就是nlogn,是不会超时的。
树状数组是利用了把数组里面的值当做tree数组里面的下标,然后get是求出i之前有多少值比a[i]小的数。
这里引用一下我哥们写的一个博客,感觉写的挺好的,力挺
我的:
#include<iostream>
#include<string>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=100000+10;
#define PI acos(-1.0)
int tree[maxn];
inline int lowbit(int x)
{
return x&(-x);
}
void add(int x,int value)
{
for(int i=x;i<=maxn;i+=lowbit(i))
{
tree[i]+=value;
}
}
int get(int x)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int main()
{
int n;
int Tcase;
scanf("%d",&Tcase);
while(Tcase--)
{
scanf("%d",&n);
int a[maxn];
for(int i=0;i<n;++i)
scanf("%d",&a[i]);
int b[maxn];
int c[maxn];
memset(tree,0,sizeof(tree));
for(int i=0;i<n;++i)
{
b[i]=get(a[i]);//找到下标i的左边比a[i]小的个数
add(a[i],1);
}
memset(tree,0,sizeof(tree));
for(int i=n-1;i>=0;--i)
{
c[i]=get(a[i]);//找到下标i的右边比a[i]小的个数
add(a[i],1);
}
long long ans=0;
// for(int i=0;i<n;i++)
// {
// cout<<b[i]<<" ";
// }
// cout<<endl;
// for(int i=0;i<n;i++)
// cout<<c[i]<<" ";
for(int i=0;i<n;++i)
{
ans+=b[i]*(n-1-i-c[i]);
ans+=c[i]*(i-b[i]);
}
printf("%lld\n",ans);
}
return 0;
}