LA 4329 Ping pong

题意:有n个兵乓球选手,每个人都有唯一的一个技能值,每场比赛需要一个裁判,这个裁判的技能值和标号都要在两个选手之间,问能够举办的比赛的种类。

思路:对于第i个人来说,如果可以求出在他左边比他技能值小的数量ai和在他右边比技能值比他小的人得数量bi,那么就可以分别算出左右两边比他技能值大的选手的数量ci和di,则当第i个人当裁判时,就有ai*di+bi*ci种比赛种类。由于技能值的范围比较小,求ai的时候可以从左到右扫描,计算在i前比它小的技能值的数量,计算方法可以使用树状数组求ai的前缀和(也可以用线段树),计算bi与ai同理,从右向左扫描即可。不过事实证明还是树状数组比较快啊,还比较好写。

 

代码:

 

树状数组实现:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
ll C[maxn],ci[maxn],di[maxn],num[maxn];
int lowbit(int x)
{
    return x&-x;
}
ll sum(int x)
{
    ll ret=0;
    while(x>0)
    {
        ret+=C[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x,int v,ll n)
{
    while(x<=n)
    {
        C[x]+=v;
        x+=lowbit(x);
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        ll res=0;
        ll maxnum=0;
        for(int i=1;i<=n;++i)
        {
            cin>>num[i];
            maxnum=max(maxnum,num[i]);
        }
        memset(C,0,sizeof(C));
        for(int i=1;i<=n;++i)
        {
            add(num[i],1,maxnum);
            ci[i]=sum(num[i])-1;
        }
        memset(C,0,sizeof(C));
        for(int i=n;i>=1;--i)
        {
            add(num[i],1,maxnum);
            di[i]=sum(num[i])-1;
        }
        for(int i=1;i<=n;++i)
        {
            res+=ci[i]*(n-i-di[i])+di[i]*(i-1-ci[i]);
        }
        cout<<res<<endl;
    }
    return 0;
}


 

线段树实现:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int N=100000;
const int maxn=(100000+10)<<1;
const int maxm=20000+10;
int C[maxn<<1],num[maxm],ci[maxm],di[maxm];
void PushUp(int rt)
{
    C[rt]=C[rt<<1]+C[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        C[rt]=0;
        return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    PushUp(rt);
}
int Query(int L,int R,int l,int r,int rt)
{
    if(l>=L&&r<=R)
    {
        return C[rt];
    }
    int sum=0;
    int m=(l+r)>>1;
    if(m>=L)
      sum+=Query(L,R,l,m,rt<<1);
    if(m<R)
      sum+=Query(L,R,m+1,r,rt<<1|1);
    return sum;
}
void Update(int p,int l,int r,int rt)
{
    if(l==r)
    {
        C[rt]+=1;
        return;
    }
    int m=(l+r)>>1;
    if(m>=p)
      Update(p,l,m,rt<<1);
    else
      Update(p,m+1,r,rt<<1|1);
    PushUp(rt);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        build(1,N,1);
        ll res=0;
        for(int i=1;i<=n;++i)
        {
            cin>>num[i];
            Update(num[i],1,N,1);
            //cout<<Query(1,num[i],1,N,1)<<endl;
            ci[i]=Query(1,num[i],1,N,1)-1;
        }
        build(1,N,1);
        for(int i=n;i>=1;--i)
        {
            Update(num[i],1,N,1);
            di[i]=Query(1,num[i],1,N,1)-1;
        }
        for(int i=1;i<=n;++i)
        {
            res+=ci[i]*(n-i-di[i])+di[i]*(i-1-ci[i]);
        }
        cout<<res<<endl;
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值