树状数组 POJ2492 Ping Pong

来源:互联网 发布:韩服fifaonline3数据库 编辑:程序博客网 时间:2024/06/05 18:15

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12089

题意:按顺序给定一些人和能量值。问按照顺序选人,中间人能量值在两边人能量值的中间,问最多有多少种选法

思路:一次AC有木有!其实是照着书上题解的思路打的。

c[i]为某a[i]处左边能量值比他小的人数和,d[i]为右边能量值比他大的人数和,然后一个简单公式即可。关键是怎样快速的求c[i]

a[i]值建树状数组,其中c[i]从前往后,d[i]从后往前(小创新,和书上不一样虽然换汤不换药),设存在的点x[a[i]] = 1,然后用不断更新数组的方式得到每个点的c[i]d[i]值。本题要求每个人能量值不重复,如果重复的话x[i]多加值就好。

不看知识点根本做不出来好嘛!其实可以这样想:如何求前一个区间和后一个区间的数值和,除了线段树,就是树状数组了!

源码:#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <queue>

#include <iostream>

using namespace std;

typedef long long ll;

int const MAXN = 100000+5;

int a[MAXN],c[MAXN],d[MAXN],x[MAXN],sum[MAXN];

int n,mmax,tmax;

ll res;

int gmax(int a,int b){return a>b?a:b;}

void init()

{

    memset(c,0,sizeof(c));

    memset(d,0,sizeof(d));

    memset(x,0,sizeof(x));

    memset(sum,0,sizeof(sum));

    tmax = mmax = res = 0;

}

int lowbit(int l)

{

    return l&-l;

}

int les(int aa)

{

    int ans = 0;

//    printf("At first , aa = %d\n",aa);

    while(aa>0){

//        printf("aa = %d\n",aa);

        ans += sum[aa];

        aa-=lowbit(aa);

    }

    return ans;

}

int big(int aa)

{

    return les(mmax) - les(aa-1);

}

void add(int aa)

{

    while(aa<=tmax){

        sum[aa]+=1;

        aa+=lowbit(aa);

    }

}

void check()

{

    int i;

    printf("c = ");

    for(i=0; i<n; i++)

        printf("%d ",c[i]);

    printf("\n d = ");

    for(i=0; i<n ;i++)

        printf("%d ",d[i]);

    printf("\n");

}

int main()

{

    int t;

    scanf("%d",&t);

    while(t--){

        init();

        scanf("%d",&n);

        for(int i=0; i<n; i++){

            scanf("%d",&a[i]);

            tmax = gmax(tmax,a[i]);

        }

        for(int i=0; i<n; i++){

            mmax = gmax(mmax,a[i]);

            x[a[i]] = 1;

            add(a[i]);

            c[i] = les(a[i]-1);

        }

//        for(int i=1; i<=mmax; i++)

//            printf("%d ",sum[i]);

//        printf("\n");

        mmax = 0;

        memset(x,0,sizeof(x));

        memset(sum,0,sizeof(sum));

        for(int i=n-1; i>=0; i--){

            mmax = gmax(mmax,a[i]);

            x[a[i]] = 1;

            d[i] = big(a[i]+1);

            res += (n-i-1-d[i])*(i-c[i])+c[i]*d[i];

            add(a[i]);

        }

//        check();

        printf("%I64d\n",res);

    }

    return 0;

}

 

0 0
原创粉丝点击