HDU - 3015 Disharmony Trees(树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3015

题意:给你n颗树的位置和高度,要求把这n棵树的位置和高度离散化以后,求 ∑ \sum_{} abs(xi-xj)*min(hi,hj)(i<j)

思路:首先将每棵树的坐标和位置按照题目的要求离散化以后,按照高度从大到小对这n棵树进行排序,那样的对于每一个i,1->i中第i棵树的h就是最小的,接下来就要考虑1->i-1与i的x的差的绝对值的和。那我们就要考虑1->i-1中比a[i].x大和比a[i].x小两部分啦,那我们就可以考虑使用树状数组求逆序对个数的思路,用一个数组sum[]存储1->i-1中比a[i].x小的个数,ans[]存储1->i-1中比a[i].x小的数的值,那我们每次计算时就可以对比a[i].x大和比a[i].x小的分开求啦,如下:

LL sum1=query(a[i].x,sum);//i之前比a[i].x小的数的个数
LL ans1=query(a[i].x,ans);//i之前比a[i].x小的数的和
LL sum2=query(n,sum);//总的个数
LL ans2=query(n,ans);//总的和
LL temp1=a[i].x*sum1-ans1;//比a[i].x小的
LL temp2=ans2-ans1-a[i].x*(sum2-sum1)//比a[i].x大的

然后每次计算完以后记得更新一下sum[]和ans[]的值就行

具体代码如下:

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

using namespace std;

#define LL long long
const int maxn=1e5+7;

struct node
{
    LL x,h;
}a[maxn];

LL X[maxn],H[maxn];

bool cmp(node aa,node bb)
{
    if(aa.h==bb.h) return aa.x<bb.x;
    return aa.h>bb.h;
}

int n;
LL sum[maxn],ans[maxn];

int lowbit(int x)
{
    return x&(-x);
}

void update(int x,LL val,LL aa[])
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        aa[i]+=val;
    }
}

LL query(int x,LL aa[])
{
    LL res=0;
    for(int i=x;i;i-=lowbit(i))
    {
        res+=aa[i];
    }
    return res;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&a[i].x,&a[i].h);
            X[i]=a[i].x,H[i]=a[i].h;
        }
        sort(X+1,X+n+1),sort(H+1,H+n+1);
        for(int i=1;i<=n;i++)
        {
            a[i].x=lower_bound(X+1,X+n+1,a[i].x)-X;
            a[i].h=lower_bound(H+1,H+n+1,a[i].h)-H;
        }

        sort(a+1,a+n+1,cmp);
        memset(sum,0,sizeof(sum));
        memset(ans,0,sizeof(ans));

        LL ANS=0;
        for(int i=1;i<=n;i++)
        {
            LL sum1=query(a[i].x,sum);
            LL ans1=query(a[i].x,ans);
            LL sum2=query(n,sum);
            LL ans2=query(n,ans);
            ANS+=(a[i].x*sum1-ans1+ans2-ans1-a[i].x*(sum2-sum1))*a[i].h;
            update(a[i].x,1LL,sum);
            update(a[i].x,a[i].x,ans);
        }
        printf("%lld\n",ANS);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值