【数据结构】POJ1990 MooFest 题解

题意

给出N头牛,每头牛因为哞(hu)声(xiang)太(shang)大(hai)而有了一个耳背值v,它们在x轴上排成一排,每头牛有一个坐标x(v,x,n<20000,没有两头牛有相同的x),如果两头牛要对话,音量为它们之间的距离abs(x[i]-x[j])*max(v[i],v[j]),求每两头牛都互相对话的音量总和(不要问我为什么它可以同时跟n-1头牛说话,我还在压牛顿的棺材板,忙得很)

分析

想n^2卡过去的,这是2004的题。

首先的一步操作是按照v值从小到大排序,然后按顺序处理,这样的话,当前这个牛与之前所有牛相比,耳背值都是取这个牛,这样就可以把之前的牛成坨处理。这是一个老套路了,在有多个关键字而且答案与下表无关的题中,常常会按照某个关键字排序,来简化问题。

接下来是如何处理v值小于等于它这一坨牛的问题,用树状数组(或线段树)来维护,存小于等于当前x值的牛数和这些牛的x值之和,这样做的话,每次处理一头牛,直接就可以求出x小于它的牛与它距离和=牛数*该牛的x值-那些牛的x之和,同理求出x大于它的牛与它距离和,然后两者加起来,乘以该牛的v,加入ans即可。这样处理完后,再将这头牛加入树状数组。

这道题主要的操作是排序以及想到将距离合在一起处理,想清楚了就觉得比较简单。

代码

#include<cstdio>
#include<algorithm>
#define MAXN 20006
using namespace std;
long long bit[MAXN][2],ans;
int n;
struct node
{
    long long v,x;
}cow[MAXN];
bool cmp(node a,node b)
{
    return a.v<b.v;
}
inline long long lowbit(long long x)
{
    return x&(-x);
}
long long addup(long long x,int op)
{
    long long sum=0;
    while(x)
    {
        sum+=bit[x][op];
        x-=lowbit(x);
    }
    return sum;
}
void change(long long x,int op,long long d)
{
    while(x<MAXN)
    {
        bit[x][op]+=d;
        x+=lowbit(x);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&cow[i].v,&cow[i].x);
    sort(cow+1,cow+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        long long scow=addup(cow[i].x,1);
        long long sx=addup(cow[i].x,0);
        ans+=cow[i].v*(scow*cow[i].x-sx);
        scow=i-1-scow;
        sx=addup(MAXN-1,0)-sx;
        ans+=cow[i].v*(sx-scow*cow[i].x);
        change(cow[i].x,1,1);
        change(cow[i].x,0,cow[i].x);
    }
    printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/Nuclear_fusion/article/details/79313557