POJ 1990 MooFest

来源:互联网 发布:php 调用jenkins 接口 编辑:程序博客网 时间:2024/05/01 05:44

题目链接:http://poj.org/problem?id=1990


题意:有n个奶牛站成一排,每只奶牛都有两个值,v和pos,如果两只奶牛i和j想传话,需要消耗max(v[i],v[j]) * | pos[i]-pos[j] |
现在求n个奶牛之间互相都传话一次,一共需要消耗多少?


思思路:答案是n*(n-1)/2个数的和,但是如果我们一个个求的话,会超时。
首先,我们规定每只奶牛贡献的答案是,它与比它v值小的奶牛所对话产生的值,这样的话可以让v值固定,而且也可以把所有情况考虑进去。每只奶牛所产生的答案变成v*(∑|pos-pos[j]|)v[j]<=v ,如果把所有的j分为左右两侧计算的话,把符合的奶牛分成左边和右边,那么就可以去掉绝对值,变成 v*( n*pos - ∑pos[j'] )+ v*( ∑pos[j'']-n*pos )
这样我们就可以用树状数组去优化这个求和。
根据公式,我们需要求距离和还有符合个数,所以我们用两个树状数组sum,num分别维护。
先统计左侧的答案:我们每次遇到一只奶牛i,那么它的左侧贡献的答案为:v[i]*( query(v[i],num)*pos[i] - query(v[i],sum) ), 累加完答案后更新树状数组。
同理,再统计右侧的答案。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>using namespace std;#define rep(i,j,k) for(int i = j; i <= k; i++ )#define Rrep(i,j,k) for(int i = j; i >= k; i-- )#define Clean(x,y) memset(x,y,sizeof(x))#define LL long longconst int maxn  =200000;int n;struct node{    int pos;    int v;}a[maxn+10];bool cmp(node a,node b){    return a.pos < b.pos;}int lowbit(int x){    return x&(-x);}void add(int x,int k,int a[]){    while( x <= maxn )    {        a[x]+=k;        x+=lowbit(x);    }}int query(int x,int a[]){    int ans = 0;    while(x)    {        ans+=a[x];        x-=lowbit(x);    }    return ans;}int sum[maxn+10];int num[maxn+10];int main(){    cin>>n;    rep(i,1,n) scanf("%d %d",&a[i].v,&a[i].pos);    sort(a+1,a+1+n,cmp);    LL ans = 0;    Clean(sum,0);    Clean(num,0);    rep(i,1,n)  //计算左侧答案考虑相等情况    {        ans+= a[i].v *( (LL)a[i].pos*query( a[i].v , num ) - query( a[i].v , sum ) );        add( a[i].v,1,num );        add( a[i].v,a[i].pos,sum );    }    Clean(sum,0);    Clean(num,0);    Rrep(i,n,1)  //计算右侧答案,只考虑严格大于的情况,否则会加重    {        ans+= a[i].v *( query( a[i].v -1  , sum ) - (LL)a[i].pos*query( a[i].v - 1 , num ) );        add( a[i].v,1,num );        add( a[i].v,a[i].pos,sum );    }    cout<<ans<<endl;    return 0;}



0 0