hdu 2492 Ping pong 线段树

给定一个序列,求出一共有多少个三元组(ai,aj,ak),使得i<j<k,ai<aj<ak。

固定中间值,查找前面比他大的有多少,比他小的有多少,查找后面比他大的有多少,比他小的有多少。

#include <stdio.h>
#include <string.h>
#define maxn 100200
#define N 20100
int sum[maxn*4];
int lmax[N],lmin[N],rmax[N],rmin[N];
int ans[N];
void pushup(int o)
{
    sum[o]=sum[o*2]+sum[o*2+1];
}

void build(int l,int r,int o)
{
    if(l==r)
    {
        sum[o]=0;
        return ;
    }
    else
    {
        int m=(l+r)/2;
        build(l,m,o*2);
        build(m+1,r,o*2+1);
        pushup(o);
    }
}

void update(int p,int l,int r,int o)
{
    if(l==r)
    {
        sum[o]++;
        return ;
    }
    int m=(l+r)/2;
    if(p<=m) update(p,l,m,o*2);
    else update(p,m+1,r,o*2+1);
    pushup(o);
}

int query(int L,int R,int l,int r,int o)
{
    if(L<=l && r<=R) return sum[o];
    int m=(l+r)/2,tot=0;
    if(L<=m) tot+=query(L,R, l,m,o*2);
    if(R>m) tot+=query(L,R, m+1,r,o*2+1);
    return tot;
}
int main()
{
    int cas;
    scanf("%d",&cas);
    int n;
    int i,j;
    while(cas--)
    {
        scanf("%d",&n);
        __int64 xx=0;
        for(i=1;i<=n;i++)
            scanf("%d",&ans[i]);
        build(1,maxn,1);
        for(i=1;i<=n;i++)
        {
            update(ans[i],1,maxn,1);
            lmax[i]=query(ans[i], maxn, 1, maxn, 1)-1;
            lmin[i]=query(1, ans[i], 1, maxn, 1)-1;
        }
        build(1,maxn,1);
        for(i=n;i>0;i--)
        {
            update(ans[i],1,maxn,1);
            rmax[i]=query(ans[i],maxn,1,maxn,1)-1;
            rmin[i]=query(1,ans[i],1,maxn,1)-1;
        }
        for(i=2;i<n;i++)
            xx=xx+lmin[i]*rmax[i]+rmin[i]*lmax[i];
        printf("%I64d\n",xx);
    }
    return 0;
}

 

posted @ 2014-07-12 14:13  贝尔摩德  阅读(270)  评论(0编辑  收藏  举报