POJ 1990 MooFest (树状数组)

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 <br> <br>* 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. <br>
 

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

Sample Input
  
  
4 3 1 2 5 2 6 4 3
 

Sample Output
  
  
57

挺不错的一道题目,题意是给出n个互不相同的点xi,每个点有一个对应的值vi,求每对点(i,j)间的abs(xi-xj)*max(vi,vj)之和,

首先,解决怎么找vi大的可以将所有点按vi排序,这样的话,我们从前往后循环,循环到的当前的数就是目前vi最大的

其次,如果是两两点间距离求绝对值相加的话太慢,那怎么求距离,这里用到树状数组,看来这是树状数组比较经典的一种用法,就是用两个树状数组tree0,tree1,sum(tree0)存放坐标比当前坐标小的点的个数,sum(tree1)存放比当前坐标小的距离的总和,可以直接求一个点与其他点距离的总和,又把距离和拆成坐标比a[i].x大的点到a[i].x距离之和与比a[i].x小的点到a[i].x距离之和

代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
#define M 20005
struct node {  //存放点信息,按v升序排列
    int v,x;
    bool operator < (const node & obj)const
    {
        return v<obj.v;
    }
}a[M];
int n;
int tree[2][M]; 
inline int lowbit(int i) {return i&(-i);}
void add(int t,int i,int v)
{
    while(i<=M)
    {
        tree[t][i]+=v;
        i+=lowbit(i);
    }
}
ll sum(int t,int i)
{
    ll res=0;
    while(i>0)
    {
        res+=tree[t][i];
        i-=lowbit(i);
    }
    return res;
}
int main()
{

    int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i].v,&a[i].x);
    }
    sort(a+1,a+n+1);
    ll sum0,sum1,t1,t2,ans=0,tot=0; //ans是结果,tot是到当前元素的已经出现过的元素的坐标之和
    for(i=1;i<=n;i++)         //i是当前处理的点,为避免两点间重复计算,所以只计算i与之前出现过的点的结果,
    {                //当前的点i是目前v最大的,但是前面元素的坐标可能分布在i的坐标的两侧
        tot+=a[i].x;
        add(0,a[i].x,1);      //维护树状数组tree0
        add(1,a[i].x,a[i].x); //维护tree1
        sum0=sum(0,a[i].x);   //sum0代表在已经出现的点中坐标比a[i].x小的个数
        sum1=sum(1,a[i].x);   //sum0代表在已经出现的点中坐标比a[i].x小的坐标之和
        t1=sum0*a[i].x-sum1;  //坐标比a[i].x小的点到a[i].x距离之和
        t2=tot-sum1-a[i].x*(i-sum0);  //坐标比a[i].x大的点到a[i].x距离之和
        ans+=(t1+t2)*a[i].v;
    }
    printf("%I64d\n",ans);
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值