HDU 3015 Disharmony Trees (线段树)

    题目大意:给定一组x[], 一组h[], 求所有的sum(min(h1,h2)*abs(x1,x2))。

    解题报告:首先,h1,h2间的较小值,我们可以将h[]从大到小排序,每次取得的h都比先前的小,计算中用到的必然是当前取得h。至于abs(x1,x2),对于当前的x,查找所有比x小的数值的和,以及个数,以及所有比x大的数值的和,和个数,计算即可。

    本题的数据规模是10W,为方便处理,可以不离散化x[]。

    另外维护一棵线段树即可。查询数量时可以使用引用,在查询和的时候一起查询。树状数组也可以做。

    代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define LL long long
#define lson l,m,pos<<1
#define rson m+1,r,pos<<1|1
#define defm int m=(l+r)>>1;
const int maxn = 111111;

int num[maxn<<2];
LL sum[maxn<<2];

void updateFather(int pos)
{
    sum[pos]=sum[pos<<1]+sum[pos<<1|1];
    num[pos]=num[pos<<1]+num[pos<<1|1];
}

void update(int p,int val,int l,int r,int pos)
{
    if(l==r)
    {
        sum[pos] = val;
        num[pos] = 1;
        return;
    }
    defm;
    if(p<=m)
        update(p,val,lson);
    else
        update(p,val,rson);
    updateFather(pos);
}

LL query(int L,int R,int l,int r,int pos)
{
    if(L<=l && r<=R)
        return sum[pos];
    defm;
    return (L<=m?query(L,R,lson):0)+(m<R?query(L,R,rson):0);
}

LL query2(int &n,int L,int R,int l,int r,int pos)
{
    if(L<=l && r<=R)
    {
        n+=num[pos];
        return sum[pos];
    }
    defm;
    return (L<=m?query2(n,L,R,lson):0)+(m<R?query2(n,L,R,rson):0);
}

struct Node
{
    int xx;
    int hh;
    int h;
    int x;
    int xindex;
} p[maxn];

bool cmpx(const Node& a,const Node& b)
{
    return a.x<b.x;
}

bool cmph(const Node& a,const Node& b)
{
    return a.h<b.h;
}

void work(int n)
{
    memset(sum,0,sizeof(sum));
    memset(num,0,sizeof(num));

    for(int i=0;i<n;i++)
        scanf("%d%d",&p[i].x,&p[i].h);

    sort(p,p+n,cmpx);
    p[0].xx=1;
    p[0].xindex = 1;
    for(int i=1;i<n;i++)
    {
        if(p[i].x == p[i-1].x)
            p[i].xx = p[i-1].xx;
        else
            p[i].xx = i+1;
        p[i].xindex = i+1;
    }

    sort(p,p+n,cmph);
    p[0].hh=1;
    for(int i=1;i<n;i++)
    {
        if(p[i].h == p[i-1].h)
            p[i].hh = p[i-1].hh;
        else
            p[i].hh = i+1;
    }

    LL res = 0;
    for(int i=n-1;i>=0;i--)
    {
        int pos = p[i].xindex;
        int ln = 0;
        LL lsum = query2(ln,1,pos,1,n,1);
        int rn = (n-1)-i-ln;
        LL rsum = query(pos,n,1,n,1);

        res+=(rsum-lsum-p[i].xx*(rn-ln))*(LL)p[i].hh;

        update(pos,p[i].xx,1,n,1);
    }

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

int main()
{
//    freopen("in.txt","r",stdin);

    int n;
    while(~scanf("%d",&n))
        work(n);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值