题目大意:
乒乓球爱好者住一排,每个人都有一定的技术值 ,
已知组成一场比赛的方式:裁判住在对手中间,且能力不能比两者同高或同低。
求可以组成多少场比赛?
解题思路:
蛮经典的线段树更新,不好理解。
。。。。。。。。。。不知道怎么讲,想好了,再来
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=100000+5;
int cnt[maxn*4];
int va[maxn];
int lmin[maxn];
int rmin[maxn];
void update(int num,int l,int r,int k)
{
if(l==r)
{
cnt[num]++;
return;
}
int mid=(l+r)/2;
if(k<=mid)
{
update(num*2,l,mid,k);
}
else
{
update(num*2+1,mid+1,r,k);
}
cnt[num]=cnt[num*2]+cnt[num*2+1];
}
int query(int num,int l,int r,int x,int y)
{
if(x<=l && y>=r)
{
return cnt[num];
}
int mid=((l+r)>>1);
int a=0,b=0;
if(x<=mid)
{
a=query(num*2,l,mid,x,y);
}
if(y>mid)
{
b=query(num*2+1,mid+1,r,x,y);
}
return a+b;
}
int main()
{
int T;
int m;
int n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
m=0;
for(int i=0;i<n;i++)
{
scanf("%d",&va[i]);
m=max(m,va[i]);
}
//cout<<m<<endl;
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++)
{
update(1,0,m,va[i]);
lmin[i]=query(1,0,m,0,va[i]-1);
}
memset(cnt,0,sizeof(cnt));
for(int i=n-1;i>=0;i--)
{
update(1,0,m,va[i]);
rmin[i]=query(1,0,m,0,va[i]-1);
}
long long ans=0;
for(int i=0;i<n;i++)
{
//cout<<lmin[i]<<" "<<rmin[i]<<endl;
ans+=lmin[i]*(n-i-rmin[i]-1)+rmin[i]*(i-lmin[i]);
}
printf("%lld\n",ans);
}
return 0;
}
/*
1
3 1 2 3
*/