HDU 3015 Disharmony Trees

本文详细解析了HDU 3015题目中的算法思路,介绍了如何通过树状数组解决该问题。文章通过具体的代码实现展示了离散化过程及树的排序和计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处忆梦http://blog.youkuaiyun.com/yimeng2013/article/details/13510899



题意:有一排树每一棵都有两个值X,H。 要求这一排树的“不和谐”值;
           计算规则:每两棵树的F*S的值之和;
           F的定义: F = abs(D1 - D2),即两棵树的x值经过排序(离散化)后的差的绝对值,排序的规则如题示例
                           x坐标为3,3,1,3,4的一排树,他们的rank值D为2,2,1,2,5
           S的定义: S = min(H1,H2),即两棵树的H值经过排序后的最小值(排序规则同上);
  
思路:将树以H值从小到大的顺序来排列,那么对于每一棵树的S就一定等于这棵树的H值。
           对于求这棵树的F值:F = (D*cnt_small - small) + (big - D*cnt_big); 
           其中的D为该棵树的D值,而cnt_small ,cnt_big为这棵树之后比它小,大的树的棵树,samll和big为这              棵树之后比它小,大的树的D值和;

           A了这道题太爽了,想了差不多三天,又花了几个小时敲,竟然1A了,感觉树状数组总算是入门了。           

           详细的构思请看代码:



#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
#define LL __int64
#define N 100000+10
int n;
LL cnt[N];
LL pre[N];

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

int sum(LL a[],int x)
{
    int ret = 0;
    while(x > 0)
    {
        ret += a[x];
        x -= lowbit(x);
    }
    return ret;
}

void add(LL a[],int x, int d)
{
    while(x <= n)
    {
        a[x] += d;
        x += lowbit(x);
    }
}

struct Node
{
    int x;
    int y;
}node[N];

int cmp1(Node a, Node b)
{
    return a.x < b.x;
}

int cmp2(Node a, Node b)
{
    return a.y > b.y;
}

int main ()
{
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d %d", &node[i].x, &node[i].y);
        }
        //离散化
        sort(node+1, node+1+n, cmp1);
        int pree = -1, rank;
        for(int i = 1; i <= n; i++)
        {
            if(node[i].x != pree)
            {    
                pree = node[i].x;
                node[i].x = i;
                 rank = i;
            }
            else
            {
                node[i].x = rank;
            }
        }



        sort(node+1, node+1+n, cmp2);
        pree = -1, rank;
        for(int i = n; i >= 1; i--)
        {
            if(node[i].y != pree)
            {
                pree = node[i].y;
                node[i].y = n - i + 1;
                rank = n - i + 1;
            }
            else
            {
                node[i].y = rank;
            }
        }

        memset(cnt, 0, sizeof(cnt));
        memset(pre, 0, sizeof(pre));
        LL ans = 0;
        for(int i = 1; i <= n; i++)
        {
            LL totle = 0;
            LL small = 0, big = 0;
            LL cnt_small = 0, cnt_big = 0;
            add(cnt, node[i].x, 1);
            add(pre, node[i].x, node[i].x);
            
            LL temp = sum(cnt,node[i].x) - sum(cnt, node[i].x-1);//计算出X值相同的树的个数

            totle = sum(pre, n);//计算出1~i棵树的x值的和
            small = sum(pre, node[i].x-1);//计算出第i棵树之前比第i棵树的x值小的树的x值之和
            big = totle - small - node[i].x*temp;//计算出第i棵树之前比第i棵树的x值大的树的x值之和
            cnt_small = sum(cnt, node[i].x-1);//计算出第i棵树之前比第i棵树小的树的个数
            cnt_big = i - cnt_small- temp ;//计算出第i棵树值前比第i棵树大的树的个数

            ans += node[i].y * ((cnt_small*node[i].x - small ) + (big - cnt_big*node[i].x));
        }
        printf("%I64d\n", ans);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值