2008 北京区域赛 ping pong // icpc 4329 ping pong

题目:
    每两人比赛需要裁判(第三名比赛队员充当),并且裁判的等级在两者之间,并且裁判需要在那两名选手的位置之间,问可以安排多少场这样的比赛。

分析:
    树状数组枚举裁判,分别求到左边位置比该队员的等级高的和等级低的选手数目,当求完之后再从左到右分别删除该项后,求到比他等级高的和等级小的,删除操作只需要modify操作时减掉1即可实现。然后根据乘法原理可知用左边的等级高的*右边等级低的+右边等级高的*左边等级低的。



#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int X = 100005;

int n,a[X];
long long r[X],l[X];
long long r_max[X],l_max[X];
long long c[X];

int lowbit(int x)
{
    return x & -x;
}

void modify(int x,int num)
{
    while(x<X)
    {
        c[x] += num;
        x += lowbit(x);
    }
}

long long query(int x)
{
    long long ans = 0;
    while(x>0)
    {
        ans += c[x];
        x -= lowbit(x);
    }
    return ans;
}

int main()
{
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(c,0,sizeof(c));

        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            l[i] = query(a[i]);
            l_max[i] = query(X-1)-l[i];
            modify(a[i],1);
        }
        for(int i=1;i<=n;i++)
        {
            modify(a[i],-1);
            r[i] = query(a[i]);
            r_max[i] = query(X-1)-r[i];
        }
        long long ans = 0;
        for(int i=1;i<=n;i++)
            ans += l[i]*r_max[i]+r[i]*l_max[i];
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2012-05-25 09:38  yejinru  阅读(290)  评论(0编辑  收藏  举报