poj1990 树状数组

1990

题意:

每头牛有两个属性v,x,计算sigma(max(v[i],v[j])*abs(x[i]-x[j]))1<=i<j<=n

分析:对于max函数我们可以按v的值从小到大排序则ans = sigma(v[j]*abs(x[i]-x[j]))1<=i<j<=n且v[i]<=v[j]

那么如何处理abs函数呢?分开来讨论

ans  = sigma(v[j]*(x[i]-x[j]))    x[i]>=x[j]

      + sigma(v[j]*(x[j]-x[i]))   x[i]<x[j]

如何快速的求得sigma的值呢?树状数组!!

这样我们就得到了算法:

先按v值从小到大排序,利用树状数组维护两个数组dist,cnt 其中dist[i] 维护的数坐标(x轴)小于等于i的距离前缀和,cnt[i]表示坐标i在当前时有没有牛(1有,0无),

维护的是当前排完序后坐标在[1,i]的牛的个数

那么排完序后枚举当前的牛i 统计在这之前坐标比牛i小的有多少l个,比它大的有多少r个,然后计算牛i到其他牛的权值(以保证牛i是当前以计算牛中v值最大)

权值= v[i]*( (l*x[i]-dist.sum(x[i]))左边的权值和 +(dist.sum(maxn)-dist.sum(x[i])-r*x[i]) 右边的权值和 )

其中dist.sum(x[i])表示当前坐标在牛i左边的所有坐标之和,那么l*x[i]就是sigma(x[i]-x[j]) x[i]>=x[j]

其中dist.sum(maxn)-dist.sum(x[i]) 就是坐标在[x[i],maxn]之间的所有牛的坐标之和  则其-r*x[i] 就是sigma(x[j]-x[i] ) x[i]<x[j]

每次算完权值后将当前的牛的信息加入树状数组里面

cnt.add(x[i],1);
dist.add(x[i],x[i]);

单点更新 cnt[x[i]]=1,dist[x[i]]=x[i]

附上代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <set>
 5 #include <algorithm>
 6 #include <map>
 7 #include <queue>
 8 #include<cmath>
 9 #include<vector>
10 #define maxn 100010
11 #define maxm 100010
12 #define mod 1000000000000000000
13 #define INF 0x3f3f3f3f
14 using namespace std;
15 typedef long long  ll;
16 inline int lowbit(int x){
17     return x&-x;
18 }
19 struct BIT{
20     int n;
21     ll bit[maxn+10];
22     void init(int N){
23         n=N;
24         for(int i=0;i<=n;++i)bit[i]=0;
25     }
26     void add(int x,int v){
27         for(int i=x;i<=n;i+=lowbit(i))bit[i]+=v;
28     }
29     ll  sum(int x){
30         ll ans=0;
31         for(int i=x;i>0;i-=lowbit(i))ans+=bit[i];
32         return ans;
33     }
34 }dist,cnt;
35 pair<int,int>cow[maxn];
36 int main (){
37     int n;
38     while(scanf("%d",&n)!=EOF){
39         dist.init(maxn);
40         cnt.init(maxn);
41         for(int i=1;i<=n;++i){
42             scanf("%d%d",&cow[i].first,&cow[i].second);
43         }
44         sort(cow+1,cow+n+1);
45         ll ans=0;
46         for(int i=1;i<=n;++i){
47             int v = cow[i].first;
48             int x = cow[i].second;
49             ll l = cnt.sum(x);//左边已有有多少个
50             ll r = cnt.sum(maxn)-cnt.sum(x);//右边已有多少个
51             ans+=v*(l*x-dist.sum(x));//左边权值和
52             ans+=v*(dist.sum(maxn)-dist.sum(x)-r*x);//右边权值和
53             cnt.add(x,1);
54             dist.add(x,x);
55         }
56         printf("%lld\n",ans);
57     }
58 }

poj1990 树状数组

时间: 2024-11-01 12:32:31

poj1990 树状数组的相关文章

MooFest(POJ-1990)(树状数组)

最近学习了一下树状数组,这道题纠结了很久,终究是因为没有明白树状数组怎么用. 感觉网上许多大神都只是讲原理,对于我们这些初学的菜鸟恐怕都被吓跑了. 这里我就以实用主义说一下使用方法(其实我觉得其原理应该能对我们更有启发,也许会带来很多潜在的好处): 这里需要注意的是,bit的实现代码中的bit数组一开始必须清零,这个数组并不是用来储存元素的,而是为实现这个数据结构而存在的.  你需要存储的元素是要通过那个add函数添加的,而求和则是要通过sum函数实现的,而这个bit数组的结构并不是对于一个新手

POJ1990 MooFest 树状数组(Binary Indexed Tree,BIT)

N头牛排成一列,每头牛的听力是Vi,每头牛的位置Pi,任意两头牛i,j相互交流时两头牛都至少需要发出声音的大小为max(Vi,Vj) * |Pi-Pj|,求这N头牛两两交流总共发出的声音大小是多少.N,V,P都是1-20000的范围. 这题首先对Vi从小到大进行排序,排序过后就可以依次计算i,将所有比Vi小的牛到i之间的距离之和乘以Vi得到Ri,然后累加Ri就是最终结果.问题是Ri具体该如何求. 假设听力比Vi小的牛并且位置也比Pi小的牛的个数为Ci,并且这些距离之和为Si,听力比Vi小的所有牛

hdu3015树状数组 poj1990的离散化版本

都是一类题目,推导调试比较烦,想出来还是不难的 /* 给定n个点对,按一维升序排序一次,每个点的序号为Di,按二维升序排序一次,每个点的序号为Hi 求sum{w(i,j)} w(i,j)=abs(Di-Dj)*min(Hi-Hj) 那么将所有的点按照H升序排列,两个树状数组,一个维护区间d的个数,一个维护区间d的总和 每个点的贡献值=树状数组中D小于其的+D大于其的abs 按升序遍历每个点后,将该点在树状数组中删掉 */ #include<bits/stdc++.h> using namesp

树状数组总结——转

转自:夏天的风 http://blog.csdn.net/shahdza/article/details/6314818#comments 又做了几道树状数组的题,决定放一块儿总结一下:恩,总结一下.. (ps:大牛可以直接跳过...) 这得从一张图说起: 树状数组中用的d[],每个点都有一定的管辖范围: 如d[1]=a[1]; d[2]=a[1]+a[2]; d[3]=a[3]; d[4]=a[1]+a[2]+a[3]+a[4]; 等等: 这样的结构关键是为了,对一个数组内部动态的删除,增加,

poj 1990 树状数组

传送门:https://vjudge.net/problem/POJ-1990 题意:m头牛,每头牛有两个值v和x.然后每两头牛之间的值是abs(x1-x2) * Max(v1,v2).问所有m*(m-1)/2对牛之间值的总和. 白书上来的.就是用树状数组做.首先肯定是按照v排序,这样就可以不用管v了.接下来我们看看x. 我们先对所有牛的x排序,然后每头牛有一个idx代表这头牛的x在所有牛的x中排第几位.然后有两个树状数组,num[N]和dis[N].num[i]表示比i小的有多少个,dis[i

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击