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;

}

 

你可能感兴趣的:(ping)