Ping pong【树状数组】

该博客讨论了一个乒乓球爱好者比赛的题目,要求裁判的技能值位于两名选手之间。提出了利用树状数组来解决此类问题的方法,通过计算每个人作为裁判时符合条件的比赛数量,最终得出总比赛数。给出了具体的AC代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Ping pong

 UVALive - 4329 

题目传送门

题目大意:一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术。每个人都有一个不同的技能值ai。每场比赛需要三个人:两名选手,一名裁判。他们有一个奇怪的规定,即裁判必须住在两名选手的中间,并且技能值也在两名选手之间。问一共能组织多少场比赛。输入第一行表示共有T组测试数据,每组数据占一行,先输入整数n(3<=n<=20000),后面跟着输入n个不同的整数,即a1,a2,a3...an(1<=ai<=100000),按照从左到右的顺序给出每个乒乓球爱好者的技能值。

解决方法:树状数组解决,考虑第i个人当裁判的情况。假设a1到ai-1中有ci个比ai小,那么就有(i-1)-ci个比ai大;同理,假设a(i+1)到an中有di个比ai小,则其中就有n-i-di个比其大,所以以ai为裁判的比赛场数为:ci*(n-i-di)+di*(i-1-ci),因此先用树状数组求每个数前面比其小的数字的数目,再反向求其后面比它小的数目,即可得到答案。

AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e6 + 5;
const ll mod = 1e9+7;
int C1[maxn];   
int C2[maxn];  
int arr[maxn];   //存技能值
int sum11[maxn];     //存的每个数前面的比其小的数目
int sum22[maxn];     //存的每个数后面比其小的数目
int n;
int lowbit(int x)
{
	return x&(-x);
}
void add1(int x,int d)
{
	while(x<=100000)
	{
		C1[x]+=d;
		x+=lowbit(x);
	}
}
int sum1(int x)
{
	int ret=0;
	while(x>0)
	{
		ret+=C1[x];
		x-=lowbit(x);
	}
	return ret;
}
void add2(int x,int d)
{
	while(x<=100000)
	{
		C2[x]+=d;
		x+=lowbit(x);
	}
}
int sum2(int x)
{
	int ret=0;
	while(x>0)
	{
		ret+=C2[x];
		x-=lowbit(x);
	}
	return ret;
}
int main() 
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    #endif
    //freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(0),cin.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
    	ms(C1);ms(C2);ms(arr);ms(sum11);ms(sum22);
    	cin>>n;
    	rep(i,1,n) {
    		cin>>arr[i];
    		add1(arr[i],1);
    		sum11[i]=sum1(arr[i]-1);
    	}
    	lep(i,n,1) {
    		add2(arr[i],1);
    		sum22[i]=sum2(arr[i]-1);
    	}
    	ll ans=0;
    	rep(i,1,n) {
    		ll c1=sum11[i];
    		ll d1=sum22[i];
    		ans+=c1*(n-i-d1)+d1*(i-1-c1);
    	}
    	cout<<ans<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值