POJ 1990 MooFest --树状数组

题意:牛的听力为v,两头牛i,j之间交流,需要max(v[i],v[j])*dist(i,j)的音量。求所有两两头牛交谈时音量总和∑(max(v[i],v[j])*abs(x[j]-x[i])) ,x[i]表示i的坐标

解法:将牛按听力从小到大排序,这样就可以使每次算一头牛与别的牛的值时听力永远取自己的听力。

建两棵树状数组,一颗维护牛的坐标,一颗维护牛的个数。

当遍历到某头牛 i 时,求出它的左边有多少头牛,记为L,右边记为R,并且算出左边的坐标之和Lsum,右边坐标值的和Rsum。

那么此时 总的和要加上 (L*x[i]-Lsum)*V[i] (左边) +  (Rsum-R*x[i])*V[i] (右边), 仔细想想就知道了。

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

using namespace std;

#define N 20007



int c[N],cnt[N],n,maxi;

struct node

{

    int val,x;

}p[N];



int cmp(node ka,node kb) { return ka.val < kb.val; }

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



void modify(int *c,int x,int val)

{

    while(x <= maxi)

        c[x] += val, x += lowbit(x);

}



int getsum(int *c,int x)

{

    int res = 0;

    while(x > 0) { res += c[x]; x -= lowbit(x); }

    return res;

}



int main()

{

    int i,j;

    while(scanf("%d",&n)!=EOF)

    {

        maxi = 0;

        for(i=1;i<=n;i++)

            scanf("%d%d",&p[i].val,&p[i].x), maxi = max(maxi,p[i].x);

        sort(p+1,p+n+1,cmp);

        memset(c,0,sizeof(c));

        memset(cnt,0,sizeof(cnt));

        lll sum = 0;

        for(i=1;i<=n;i++)

        {

            int L = getsum(cnt,p[i].x);

            int R = getsum(cnt,maxi) - getsum(cnt,p[i].x-1);

            int Lsum = getsum(c,p[i].x);

            int Rsum = getsum(c,maxi) - getsum(c,p[i].x-1);

            sum += 1LL*(p[i].x*L-Lsum)*p[i].val;

            sum += 1LL*(Rsum-p[i].x*R)*p[i].val;

            modify(c,p[i].x,p[i].x);

            modify(cnt,p[i].x,1);

        }

        cout<<sum<<endl;

    }

    return 0;

}
View Code

 

你可能感兴趣的:(树状数组)