poj 1990 MooFest 树状数组

题意就是有N头牛,每头牛都有一个坐标和声调值(x, v),两头牛之间通讯要花费的能量是他们的距离乘以最大的一个音调值,现在要任意两头牛之间都相互通讯一次,求总共需要花费多少能量?

      显然总共有n*(n+1)/2条,我们可以用树状数组保存,树状数组很适合求区间的和,我们只需要求出某头牛左右两边分别有多少头牛比它的音调小,且他们的坐标和,这样我们就能求出这头牛到其他牛之间的距离和了,因为它的音调值已知且在这先中最大,然后这要求出一头牛与其他比他小的通讯花费的能量了,然后以此求出其他的。这样计算出了它小的,遍历一遍后必然每头牛之间都有里通讯。

#include<iostream>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
const int MAX = 20005;
 
struct data{
    int x, w;
}cow[MAX];
int arNum[MAX], arDis[MAX];
 
bool cmp(data a, data b){
    return a.x < b.x;
}
 
void add(int i, int *ar, int w){
    while(i <= MAX-1){
        ar[i] += w;
        i += lowbit(i);
    }
}
 
__int64 sum(int i, int *ar){
    __int64 ans = 0;
    while(i > 0){
        ans += ar[i];
        i -= lowbit(i);
    }
    return ans;
}
 
int main(){
    int n, i;
    __int64 preNum, preDis;
    scanf("%d", &n);
    for(i = 0; i < n; i ++)
        scanf("%d%d", &cow[i].w, &cow[i].x);
    sort(cow, cow + n, cmp);
    __int64 ans = 0;
    memset(arNum, 0, sizeof(arNum));          //  求向左的总能量。
    memset(arDis, 0, sizeof(arDis));
    for(i = 0; i < n; i ++){
        preNum = sum(cow[i].w-1, arNum);
        preDis = sum(cow[i].w-1, arDis);
        ans += (preNum * cow[i].x - preDis) * cow[i].w;
        add(cow[i].w, arNum, 1);
        add(cow[i].w, arDis, cow[i].x);
    }
    memset(arNum, 0, sizeof(arNum));          //  求向右的总能量。
    memset(arDis, 0, sizeof(arDis));
    for(i = n-1; i >= 0; i --){
        preNum = sum(cow[i].w, arNum);        //  这里不要用w-1,考虑了声调相等的情况。
        preDis = sum(cow[i].w, arDis);
        ans += (preDis - preNum * cow[i].x) * cow[i].w;
        add(cow[i].w, arNum, 1);
        add(cow[i].w, arDis, cow[i].x);
    }
    printf("%I64d\n", ans);
    return 0;
}


POJ 2182是一道使用树状数组解决的题目,题目要求对给定的n个数进行排序,并且输出每个数在排序后的相对位置。树状数组是一种用来高效处理前缀和问题的数据结构。 根据引用中的描述,我们可以通过遍历数组a,对于每个元素a[i],可以使用二分查找找到a到a[i-1]中小于a[i]的数的个数。这个个数就是它在排序后的相对位置。 代码中的query函数用来求前缀和,add函数用来更新树状数组。在主函数中,我们从后往前遍历数组a,通过二分查找找到每个元素在排序后的相对位置,并将结果存入ans数组中。 最后,我们按顺序输出ans数组的元素即可得到排序后的相对位置。 参考代码如下: ```C++ #include <iostream> #include <cstdio> using namespace std; int n, a += y; } } int main() { scanf("%d", &n); f = 1; for (int i = 2; i <= n; i++) { scanf("%d", &a[i]); f[i = i & -i; } for (int i = n; i >= 1; i--) { int l = 1, r = n; while (l <= r) { int mid = (l + r) / 2; int k = query(mid - 1); if (a[i > k) { l = mid + 1; } else if (a[i < k) { r = mid - 1; } else { while (b[mid]) { mid++; } ans[i = mid; b[mid = true; add(mid, -1); break; } } } for (int i = 1; i <= n; i++) { printf("%d\n", ans[i]); } return 0; } ``` 这段代码使用了树状数组来完成题目要求的排序功能,其中query函数用来求前缀和,add函数用来更新树状数组。在主函数中,我们从后往前遍历数组a,通过二分查找找到每个元素在排序后的相对位置,并将结果存入ans数组中。最后,我们按顺序输出ans数组的元素即可得到排序后的相对位置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [poj2182Lost Cows——树状数组快速查找](https://blog.csdn.net/aodan5477/article/details/102045839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [poj_2182 线段树/树状数组](https://blog.csdn.net/weixin_34138139/article/details/86389799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xindoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值