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

Time Limit: 1000MS
Memory Limit: 30000K

Total Submissions: 8141
Accepted: 3674

Description

Every year, Farmer John‘s N (1 <= N <= 20,000) cows attend "MooFest",a social gathering of cows from around the world. MooFest involves a variety of events including haybale stacking, fence jumping, pin the tail on the farmer, and of course, mooing. When the cows all stand in line for a particular event, they moo so loudly that the roar is practically deafening. After participating in this event year after year, some of the cows have in fact lost a bit of their hearing.
Each cow i has an associated "hearing" threshold v(i) (in the range 1..20,000). If a cow moos to cow i, she must use a volume of at least v(i) times the distance between the two cows in order to be heard by cow i. If two cows i and j wish to converse, they must speak at a volume level equal to the distance between them times max(v(i),v(j)).
Suppose each of the N cows is standing in a straight line (each cow at some unique x coordinate in the range 1..20,000), and every pair of cows is carrying on a conversation using the smallest possible volume.
Compute the sum of all the volumes produced by all N(N-1)/2 pairs of mooing cows.

Input

* Line 1: A single integer, N
* Lines 2..N+1: Two integers: the volume threshold and x coordinate for a cow. Line 2 represents the first cow; line 3 represents the second cow; and so on. No two cows will stand at the same location.

Output

* Line 1: A single line with a single integer that is the sum of all the volumes of the conversing cows.

Sample Input

4
3 1
2 5
2 6
4 3

Sample Output

57

Source

USACO 2004 U S Open

题意:

给定一个序列,序列两点之间的花费为 两点之间的距离*(两点之间价值大者),求所有N(N-1)/2个点对的花费之和

思路:

对某个点来说,其等级可以作为乘数的情况是 它与它左右两边比它的等级小的组成点对

设某个点,坐标为 Xc,它的等级为val,其左边比它小的有n1个,右边比它小的有n2个,左边比比它小的坐标为Xi(1<=i<=n1),右边比它小的坐标为 Xj(1<=j<=n2)

则经过推导,我们可以得到其对答案的贡献为:

(n1-n2) * Xc * val + val ( segma(Xi) – segma(Xj) )

所以我们需要统计两个类型的值:左右两边比它等级小的点的个数,左右两边比它等级小的点的坐标和。

这两个类型的值需要分别求出来,但只要知道了其中一个就可得到另外一个(知道了左边的就可以推导出右边的)

我们利用树状数组来统计这些值,具体做法如下:

将所有点按照等级排序,则某个点现在的标号即为比它小的所有点(包括左和右)的总个数。

我们使用两个树状数组,从左到右一次插入每个节点,一个树状数组统计左边比它等级小的点的个数,另一个统计点的坐标和

第一个树状数组好理解,主要困难在于构造第二个树状数组

只需要每次 update(x[i], x[i])即可

这样的话, x[i] 插入之前,getsum(x[i])就是左边比i点等级小的点的坐标和

代码:

  1 /*
  2 * @FileName: D:\代码与算法\2017训练比赛\七月训练四\1013.cpp
  3 * @Author: Pic
  4 * @Date:   2017-08-04 21:31:01
  5 * @Last Modified time: 2017-08-05 20:21:10
  6 */
  7
  8 #include <iostream>
  9 #include <algorithm>
 10 #include <cstdio>
 11 #include <string.h>
 12 #include <queue>
 13 using namespace std;
 14 typedef __int64 ll;
 15 const int MAXN=20000+30;
 16 //注意,这道题的vol有相同的情况出现。这样的话就不能先按x坐标排序,统计左右比这个点小的个数,然后按照vol排序统计左右比这个点小的点的vol和
 17 //而是应该同步地统计这两个量,防止相同的情况
 18 struct BIT{
 19 	void init()
 20 	{
 21 		memset(Tree_sum,0,sizeof(Tree_sum));
 22 	}
 23 	ll Tree_sum[MAXN];//存储树状数组的数组
 24 	//int maxn=20000+30;  //树状数组的下标最大值
 25 	ll lowbit(ll x)   //lowbit函数, 找到x与与 *最近的一个末位连续0比他多的数* 的距离
 26 	{
 27 	    return x&(-x);
 28 	}
 29 	ll getsum(ll x)   //获取0至x区间的和
 30 	{
 31 	    ll sum=0;
 32 	    for(;x>0;x-=lowbit(x)){
 33 	        sum+=Tree_sum[x];
 34 	    }
 35 	    return sum;
 36 	}
 37 	void update(ll x,ll v)    //更新某点的值
 38 	{
 39 	    for(;x<=MAXN;x+=lowbit(x)){
 40 	        Tree_sum[x]+=v;
 41 	    }
 42 	}
 43 };
 44 BIT tr,tr2;
 45 struct node
 46 {
 47 	ll vol,x,id;
 48 }a[MAXN];
 49 ll n1[MAXN];
 50 bool cmp(node a,node b)
 51 {
 52     return a.vol<b.vol;
 53 }
 54 bool cmp1(node a,node b)
 55 {
 56 	return a.x<b.x;
 57 }
 58 int main(){
 59     //freopen("data.in","r",stdin);
 60 	ll n;
 61 	while(~scanf("%I64d",&n)){
 62 		for(int i=0;i<n;i++){
 63 			//scanf("%d%d",&a[i].vol,&a[i].x);
 64 			//cin>>a[i].vol>>a[i].x;
 65 			scanf("%I64d%I64d",&a[i].vol,&a[i].x);
 66 			a[i].id=i;
 67 		}
 68 		tr.init();
 69 		tr2.init();
 70 		sort(a,a+n,cmp1);
 71         sort(a,a+n,cmp);
 72         ll res=0,sum=0,sumn=0;
 73         for(int i=0;i<n;i++){
 74         	sumn=tr.getsum(a[i].x);
 75             ll suma=tr2.getsum(a[i].x);
 76             res+=((sum-suma-suma)*a[i].vol);
 77             res+=((2*sumn-i)*a[i].vol*a[i].x);
 78             //cout<<res<<endl;
 79             tr2.update(a[i].x,a[i].x);
 80             tr.update(a[i].x,1);
 81             sum+=a[i].x;
 82         }
 83         //printf("%lld\n",res);
 84         //cout<<res<<endl;
 85         printf("%I64d\n",res);
 86 	}
 87     return 0;
 88 }

时间: 2024-10-27 13:12:40

POJ1990--POJ 1990 MooFest(树状数组)的相关文章

POJ 1990 MooFest 树状数组

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

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小的所有牛

POJ 2309 BST 树状数组基本操作

Description Consider an infinite full binary search tree (see the figure below), the numbers in the nodes are 1, 2, 3, .... In a subtree whose root node is X, we can get the minimum number in this subtree by repeating going down the left node until t

Poj 2299 Ultra-QuickSort 树状数组 解法

本题的树状数组稍微有点特点,就是需要所谓的离散化一下,开始听这个名称好像很神秘的,不过其实很简单. 就是把一个数组arr的值,其中的值是不连续的,变成一组连续的值,因为这样他们的顺序是不变的,所以,不影响结果. 例如:9 1 0 5 4 ->变为:5 2 1 4 3看出他们的相对位置不变的. 9和5为最大值在第一个位置,1和2为第二大的值在第二个位置,0和1在第一个位置等,看出对应顺序了吗? 对,就是这么简单的方法, 就叫做离散化. 如果你对counting sort熟悉的话,那么这样的思想理解

POJ 2481 Cows(树状数组)

Description Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good. Farmer John has N cows (we number the cows from 1 to N). Ea

POJ 2352 Stars(树状数组 or 线段树)

链接: http://poj.org/problem?id=2352 题目大意: 在坐标上有n个星星,如果某个星星坐标为(x, y), 它的左下位置为:(x0,y0),x0<=x 且y0<=y.如果左下位置有a个星星,就表示这个星星属于level x 按照y递增,如果y相同则x递增的顺序给出n个星星,求出所有level水平的数量. 思路: 由于输入的顺序,对于第i颗星星,它的等级是之前输入的星星中,横坐标x小于等于i星横坐标的那些星星的总数量(前面的y一定比后面的y小). 所以是查询+更新操作

poj 2481 Cows 树状数组解法,详细解析。

Cows Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13445   Accepted: 4448 Description Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in hi

POJ 2481 Cows &amp;&amp; POJ 2352 Stars(树状数组妙用)

题目链接:POJ 2481 Cows POJ 2352 Stars 发现这两个题目都跟求逆序数有着异曲同工之妙,通过向树状数组中插入点的位置,赋值为1,或者++,然后通过求和来判断比当前 点 "小" 的有多少点. Cows需要自己排序, Stars题目已经给排好序. POJ 2352 Stars 题目大意为在二维坐标上给出一些星星的坐标,求某一个星星左方,下方,左下方的星星个数.题目已经把星星按照Y坐标从小到大,X从小到大排序.因此,在每次对一个星星进行统计时,之前出现过的星星,只要X

POJ 2299 Ultra-QuickSort(树状数组 + 离散)

链接:http://poj.org/problem?id=2299 题意:给出N个数组成的数列A(0 <= A[i] <= 999,999,999),求该数列逆序对的数量. 分析:题目所谓的排序过程其实就是一个冒泡排序的过程.在这里,我们需要知道,冒泡排序所需交换的次数等于该序列逆序对的数量(证明略).这是这道题的一个切入点. 树状数组可以很方便地求出数列的前缀和,对于一个数x,我们使树状数组上第x个元素的值赋为1,这时调用Sum(x)就可以得到一个从第1项到第x项的前缀和.这意味着我们可以通

POJ 2352 【树状数组】

题意: 给了很多星星的坐标,星星的特征值是不比他自己本身高而且不在它右边的星星数. 给定的输入数据是按照y升序排序的,y相同的情况下按照x排列,x和y都是介于0和32000之间的整数.每个坐标最多有一个星星. 思路: 这题给的输入数据很祥和,间接提示思路了. 用x作为树状数组的区间,然后按照输入的顺序不断查找在包括自己的位置以及左边的星星数. 细节是x可能是0,这是树状数组不能接受的,需要对输入的x数据进行加一操作. 从这题可以看出树状数组最直白的作用就是求从1开始到某个点的某个区间的数量. #