树状数组(acm hdu 5792)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5792

题意:给你一串数组A,要求 abcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad abcd,Aa<Ab,Ac>Ad



题解:先只考虑 Aa<Ab,Ac>Ad 的情况,然后一个一个排除掉a==c a==d b==c b==d 这四种情况

要建立4个数组,left_low,left_high,right_high,right_low,如意,已left_low,为例,left_low[i]就是i左边(按输入的顺序)比i对应的数值小的数字有多少个,用树状数组来查,压缩到o(nlogn),建立完之后就通过如代码上的关系来进行计算(可自己推断出)

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;
typedef struct
{
    int value;
    int w;
}Test;
Test test[50005];
int value[50005];
int c[50005];
int left_high[50005];
int left_low[50005];
int right_high[50005];
int right_low[50005];
bool compare(Test a,Test b)
{
    return a.value>b.value;
}
int lowerbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=lowerbit(i))
    {
        sum+=c[i];
    }
    return sum;
}
void add(int x,int val,int n)
{
    for(int i=x;i<=n;i+=lowerbit(i))
    {
        c[i]+=val;
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++) {scanf("%d",&test[i].value);test[i].w=i;}
        sort(test+1,test+n+1,compare);
        for(int i=1;i<=n;i++){value[test[i].w]=i;if(i+1<=n&&test[i].value==test[i+1].value){
            for(int j=i+1;j<=n;j++)
            {
                value[test[j].w]=i;
                if(test[j].value!=test[j+1].value){i=j;break;}
            }
        }}
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            left_high[i]=sum(value[i]-1);
            left_low[i]=i-1-sum(value[i]);
            add(value[i],1,n);
        }
        memset(c,0,sizeof(c));
        for(int i=n;i>0;i--)
        {
            right_high[i]=sum(value[i]-1);
            right_low[i]=sum(n)-sum(value[i]);
            add(value[i],1,n);
        }

        long long ans1=0;
        long long ans2=0;
        for(int i=1;i<=n;i++)
        {
            ans1+=right_low[i];
            ans2+=right_high[i];
        }
        ans1*=ans2;

        ans2=0;
        for(int i=1;i<=n;i++)
        {
            ans2+=right_high[i]*right_low[i];
            ans2+=left_high[i]*right_high[i];
            ans2+=left_low[i]*right_low[i];
            ans2+=left_high[i]*left_low[i];
        }

        ans1-=ans2;
        printf("%lld\n",ans1);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值