版权声明:转载请注明出处。 https://blog.csdn.net/u014427196/article/details/41038245

题目大意:一群牛参加完牛的节日后都有了不同程度的耳聋,第i头牛听见别人的讲话,别人的音量必须大于v[i],当两头牛i,j交流的时候,交流的最小声音为max{v[i],v[j]}*他们之间的距离。现在有n头牛,求他们之间两两交流最少要的音量和。

解题思路:一开始水水的写了一个n^2的算法,这题终究没有那么白痴。原来是用了树状数组。首先将这n头牛按照v值从小到大排序(后面说的排在谁的前面,都是基于这个排序)。这样,排在后面的牛和排在前面的牛讲话,两两之间所用的音量必定为后面的牛的v值,这样一来才有优化的余地。然后,对于某头牛i来说,只要关心跟排在他前面的牛交流就好了。我们必须快速地求出排在他前面的牛和他之间距离的绝对值只和ans,只要快速地求出ans,就大功告成。这里需要两个树状数组。树状数组可以用来快速地求出某个区间内和,利用这个性质,我们可以快速地求出对于牛i,x位置比i小牛的个数,以及这个牛的位置之和。这里就需要两个树状数组,一个记录比x小的牛的个数a,一个记录比x小的牛的位置之和b,然后,我们可以快速地求出牛i和比牛i位置小的牛的所有距离的绝对值为:ax[i]-b;也可以方便地求出比牛i位置大的牛到牛i的距离和,即所有距离-b-(i-1-a)x[i];那么此题就差不多了。

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#include<algorithm>
#include<vector>
#include<string.h>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<sstream>
#include<time.h>
#include<utility>
#include<malloc.h>
#include<stdexcept>

using namespace std;

int n;

struct q
{
    int v;
    int x;
}p[20005];

int a[20005];
int b[20005];

bool cmp (q a,q b)
{
    if (a.v != b.v)
        return a.v <= b.v;
}

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

void add(int i,int v,int *a)
{
    while (i<=20004)//求所有牛总和
    {
        a[i] += v;
        i+=lowbit(i);
    }
}

int sum (int i,int *a)
{
    long long ans =0;
    while (i>0)
    {
        ans += a[i];
        i-=lowbit(i);
    }
    return ans;
}

int main()
{
    while ( scanf("%d",&n)!=EOF )
    {
        memset (a,0,sizeof(a));
        memset (b,0,sizeof(b));

        for (int i=1;i<=n;i++)
        {
            scanf("%d %d",&p[i].v,&p[i].x);
        }

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

        long long  ans = 0;
        long long  dis1;
        long long num1;
        long long alldis=0;

        long long  all=0;;

        for (int i=1;i<=n;i++)
        {
            dis1 = sum( p[i].x ,a);
            num1 = sum( p[i].x ,b);

            ans += p[i].v * ( num1 * p[i].x - dis1 + all- dis1-(i-num1-1)*p[i].x );

            add( p[i].x , p[i].x ,a);
            add( p[i].x , 1,b);

            all += p[i].x;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}