POJ 1990 MooFest 树状数组

  这题是我看了大白书树状数组后刷的第一道题,确实难度不小,所以只好上网找题解了,网上的做法确实精彩。这题的题意主要是有N头牛,每两头牛之间交流的费用为它们的距离乘上两者音量的最大值(即max(v(i),v(j))),然后统计所有牛两两交流的总费用。一开始能想到的做法便是O(n2)的暴力枚举了,当时的我也只能想到这样的复杂度,很纳闷怎么能和树状数组搭上边呢?然后看了别人的题解后才惊叹其思路之妙。

  在博客 http://www.cnblogs.com/Fatedayt/archive/2011/10/08/2202439.html 上说得很详细,附上其主要的思路:

  已经说得很详细了,即统计某头牛i 时,通过排序和预处理可以把原本的O(n)查询下降到O(logn),确实很厉害,也很难想到。我结合网上其他人的题解半抄半改写出如下代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long LL;
 6 const int maxn= 20020;
 7 
 8 inline LL lowbit(LL x)    {    return x&(-x);    }
 9 
10 struct treeArray{
11     LL c[maxn], n;
12     treeArray(LL n= 0): n(n) {    memset(c,0,sizeof(c));    }
13     LL sum(LL x) {
14         LL ans= 0;
15         while(x){
16             ans+= c[x];
17             x-= lowbit(x);
18         }
19         return ans;
20     }
21     void add(LL x, LL d){
22         while(x<=n){
23             c[x]+= d;
24             x+= lowbit(x);
25         }
26     }
27 } Count(20003),dist(20003);
28 
29 struct Cow{
30     LL v,x;
31     bool operator <(const Cow c2) const {
32         return v<c2.v;
33     }
34 } cow[maxn];
35 
36 int main(){
37     int n,i;
38     scanf("%d",&n);
39     for(i=1; i<=n; ++i)
40         scanf("%lld%lld",&cow[i].v,&cow[i].x);
41     sort(cow+1,cow+n+1);
42     LL ans= 0, alldist= 0;
43     for(i=1; i<=n; ++i){
44         LL x = cow[i].x;
45         LL num = Count.sum(x);
46         LL lessdist = dist.sum(x);
47         ans += cow[i].v*(num*x-lessdist+alldist-lessdist-(i-1-num)*x);
48         Count.add(x,1);
49         dist.add(x,x);
50         alldist += x;
51     }
52     printf("%lld\n",ans);
53     return 0;
54 }

  其中,Count.sum(x)表示统计比x小的牛的个数(在上图中就是a),dist.sum(x)表示统计比x小的牛的位置之和(在上图中为b);alldist即前i 头牛的所有距离(可以认为是以原点作为标准),其余的变量名也不难理解。码完后才感到树状数组真是太强大了,不得不赞!

转载于:https://www.cnblogs.com/Newdawn/p/4161986.html

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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值