poj1990

题意:有n头牛排成一列,每头牛都有它自己的声调 v 和坐标 x ,两头牛交流消耗的能量为 max(v1,v2)*这两头牛之间的距离,求令这n头牛两两交流共消耗的能量。


解题思路:按音调从低到高排成一列,这样对于每头牛来说只需考虑它前面的牛就可以了,对于牛 i,前面牛的坐标可能大于也可能小于这头牛 ,所以需要两个树状数组 ,一个存放坐标,一个存放数量,令 

   down_sum表示小于等于此头牛的坐标之和

   up_sum表示大于此头牛的坐标之和

   down_num表示坐标小于等于此头牛的数量之和

   up_sum表示坐标大于此头牛的数量之和;


 那么 rel+=cow[i].v * (down_num*cow[i].x -down_sum)  // 坐标小于此头牛的能量之和

          rel+=cow[i].v * (up_sum - up_num * cow[i].x)        // 坐标大于此头牛的能量之和


wa了好几次,原因是MAX开小了,若向上更新的话,MAX一定要大于20000*2;若用total记录总坐标之和的话,时间复杂度会降低,而且只需向下更新,MAX开到20000+1就可以了。


样例过了但不知道错在哪的话,就自己多写一些极限情况下的数据进行测试。


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#define MAX 1<<16
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;

ll N;
P cow[MAX];
ll up_tree[MAX];
ll down_tree[MAX];
ll num[MAX];

ll sum(ll *tree,ll a){
   ll ans=0;
   while(a>0){
      ans+=tree[a];
      a-=a&-a;
   }
   return ans;
}

void add(ll *tree,ll n,ll x){ ///向上更新
   while(n<=MAX-1){
      tree[n]+=x;
      n+=n&-n;
   }
}

int main(){
 //  freopen("A.txt","r",stdin);
   cin>>N;
   for(ll i=1;i<=N;i++)
     cin>>cow[i].first>>cow[i].second;
   sort(cow+1,cow+N+1);

   ll down_sum=0,up_sum=0; ///初始化
   ll down_num=0,up_num=0;
   ll rel=0;
   memset(num,0,sizeof(num));
   memset(down_tree,0,sizeof(down_tree));

   for(ll i=1;i<=N;i++){
      add(down_tree,cow[i].second,cow[i].second);
      down_sum=sum(down_tree,cow[i].second);///小于cow[i].second的坐标之和
      up_sum=sum(down_tree,MAX-1)-down_sum;

      add(num,cow[i].second,1);
      down_num=sum(num,cow[i].second); ///坐标小于cow[i].second的数量之和
      up_num=sum(num,MAX-1)-down_num;

      rel+=cow[i].first*(down_num*cow[i].second-down_sum); ///左半部分消耗能量
      rel+=cow[i].first*( up_sum - up_num*cow[i].second ); ///右半部分消耗能量
   }
   cout<<rel;
   return 0;
}




   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值