1. 程式人生 > >MooFest POJ - 1990 (樹狀陣列)

MooFest POJ - 1990 (樹狀陣列)

傳送門

題意:給出牛的耳聾程度和牛所在的位置,之後求出每兩個牛所能聽到對方的聲音的和,每兩個牛的計算公式為max(vi,vj)*|xi-xj|

題解:首先暴力肯定是不行的,那麼可以按照牛的音量進行從小到大排序,然後維護兩個樹狀陣列,一個維護此位置之前之後的牛的個數,另一個維護此位置之前之後的牛的位置之和,之後求和即可.

附上程式碼:


#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

typedef long long ll;

const int maxn=2e4+50;

pair<int,int>cow[maxn];
int n;
ll cnt[maxn],dis[maxn];

int lowbit(int i)
{
    return i&(-i);
}

ll sum(ll *bit,int i)
{
    ll res=0;
    while(i>0){
        res+=bit[i];
        i-=lowbit(i);
    }
    return res;
}

ll sum(ll *bit,int from,int to)
{
    return sum(bit,to)-sum(bit,from);
}

void add(ll *bit,int i,ll x)
{
    while(i<=maxn){
        bit[i]+=x;
        i+=lowbit(i);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d%d",&cow[i].first,&cow[i].second);
    }
    sort(cow,cow+n);
    ll ans=0;
    for(int i=0;i<n;i++){
        int v=cow[i].first,x=cow[i].second;
        int lcnt=sum(cnt,0,x),rcnt=sum(cnt,x,maxn);
        ans+=v*((x*lcnt-sum(dis,0,x))+(sum(dis,x,maxn)-rcnt*x));
        add(cnt,x,1);
        add(dis,x,x);
    }
    printf("%lld\n",ans);
    return 0;
}