UVA-1428 - Ping pong(树状数组)

题意:有N个乒乓球运动员,他们每个人都有自己的技能值,且各不相等。

现在问你从中选出两个运动员和一个教练组成一场比赛,且要求教练要在两个运动员中间,教练的技能值也要在两个运动员之间。

分析:假设选中A[i]当作教练,则我们需要知道A[0]~A[i-1]有ai个小于A[i],者我只需对前i个插入树状数组中有几个小于A[i]几个,也就是求1~A[i]的前缀和。。同理也可以从右往左再用一遍树状数组,即可得A[i+1]~A[n-1]有bi个大于A[i]。。Si=ai*bi+(i-ai)*(n-i-1-bi),再求S和,我们就可以得到结果。

感觉自己的文字描述语言弱爆了。。。!!!请原谅

// File Name: 1428.cpp
// Author: zlbing
// Created Time: 2013/3/9 0:33:32

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,n) for(int i=0;i<n;i++)
#define REP1(i,n) for(int i=1;i<n+1;i++)
const int MAXN=1e5+50;
int G[MAXN];
int C[MAXN];
int A[MAXN],B[MAXN];
int lowbit(int x){
    return x&-x;
}
int sum(int x){
    int ret=0;
    while(x>0){
        ret+=C[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x,int d){
    while(x<MAXN){
        C[x]+=d;
        x+=lowbit(x);
    }
}
int main(){
    int cas;
    scanf("%d",&cas);
    while(cas--){
        int N;
        scanf("%d",&N);
        REP(i,N)scanf("%d",&G[i]);
        CL(C,0);
        CL(A,0);
        CL(B,0);
        REP(i,N){
            A[i]+=sum(G[i]);
            add(G[i],1);
        }
        CL(C,0);
        for(int i=N-1;i>=0;i--){
            B[i]+=N-i-1-sum(G[i]);
            add(G[i],1);
        }
        LL ans=0;
        REP(i,N)
            ans+=A[i]*B[i]+(i-A[i])*(N-i-1-B[i]);
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2013-03-09 18:57  z.arbitrary  阅读(297)  评论(0编辑  收藏  举报