UVALive 4329 树状数组第二题

大白书上的题目,比较巧妙的是其分析,为了求某个i点做裁判的时候的情况数,只要知道左边有多少比它小的记为ansc,右边有多少比它小的记为ansd,则总种数,必定为

ansc*(右边总数-ansd)+ansd*(左边总数-ansc)。

为了速度求出ansc和ansd,用到树状数组,这倒不是很难得地方,每次读到a[i],更新a[i]值+1即可。反过来求一次即可求出来 ansd

注意最后数据可能超过32位整数,因此用long long

树状数组的使用还有些不熟练。。。要继续加强

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int x[100005];
long long n,a[20010],c[100010];
long long ansc[20010],ansd[20010];
int lowbit(int q)
{
    return q&(-q);
}
long long sum(int q)
{
    long long ret=0;
    while (q>0)
    {
        ret+=c[q];
        q-=lowbit(q);
    }
    return ret;
}
void add(int loc,int d,int maxn)
{
    while (loc<=maxn)
    {
        c[loc]+=d;
        loc+=lowbit(loc);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    long long maxn=0;
    while (t--)
    {
        scanf("%lld",&n);
        for (int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            maxn=max(maxn,a[i]);
        }
        memset(c,0,sizeof c);
        for (long long i=1;i<=n;i++)
        {
            //x[a[i]]=1;
            add(a[i],1,maxn);
            ansc[i]=sum(a[i]-1);
        }
        memset(c,0,sizeof c);
        for (long long i=n;i>=1;i--)
        {
            //x[a[i]]=1;
            add(a[i],1,maxn);
            ansd[i]=sum(a[i]-1);
        }
        long long ans=0;
        for (long long i=1;i<=n;i++)
        {
            ans+=ansc[i]*(n-i-ansd[i])+ansd[i]*(i-ansc[i]-1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2014-03-11 23:46  KRisen  阅读(252)  评论(0编辑  收藏  举报