zoukankan      html  css  js  c++  java
  • 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
    ",res);
     84         //cout<<res<<endl;
     85         printf("%I64d
    ",res);
     86 	}
     87     return 0;
     88 }
    View Code
  • 相关阅读:
    系统程序员成长计划内存管理(一)
    系统程序员成长计划工程管理(二)
    嵌入式GUI ftk0.3发布
    嵌入式GUI FTK设计与实现目录
    嵌入式GUI FTK设计与实现分层视图
    sql 临时表的问题
    解惑XP系统IIS无法添加映射之诡异现象
    C#高质量缩略图
    C#图片处理之另存为压缩质量可自己控制的JPEG
    SQL注入
  • 原文地址:https://www.cnblogs.com/liuzhanshan/p/7295911.html
Copyright © 2011-2022 走看看