洛谷P2345 奶牛集会

题目背景

MooFest, 2004 Open

题目描述

约翰的N 头奶牛每年都会参加“哞哞大会”。哞哞大会是奶牛界的盛事。集会上的活动很

多,比如堆干草,跨栅栏,摸牛仔的屁股等等。它们参加活动时会聚在一起,第i 头奶牛的坐标为Xi,没有两头奶牛的坐标是相同的。奶牛们的叫声很大,第i 头和第j 头奶牛交流,会发出max{Vi; Vj}×|Xi − Xj | 的音量,其中Vi 和Vj 分别是第i 头和第j 头奶牛的听力。假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。

输入输出格式

输入格式:

 

• 第一行:单个整数N,1 ≤ N ≤ 20000

• 第二行到第N + 1 行:第i + 1 行有两个整数Vi 和Xi,1 ≤ Vi ≤ 20000; 1 ≤ Xi ≤ 20000

 

输出格式:

 

• 单个整数:表示所有奶牛产生的音量之和

 

输入输出样例

输入样例#1:
4
3 1
2 5
2 6
4 3
输出样例#1:
57
分析:这道题如果看数据范围O(n^2)是不能过的,但是如果先按照v排序,再来暴力就能A掉,但是有没有更好的方法呢?因为已经按照v排序了,所以排除v的干扰,关键就是怎么快速求sum{|xi - xj|},绝对值化简出来要么是xi - xj,要么是xj - xi,那么我们找i之前有多少个比i小的num1,它们的和是多少x1,有多少个比i大的num2,它们的和是多少x2,那么很显然,ans += v * (num1 * x - x1 + x2 - num2 * x).那么怎么快速求出num和x1,x2呢?很显然,树状数组。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

long long n,c[50010],maxn,num[50010],ans;

struct node
{
    long long v,x;
}e[20010];

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

void add(long long x,long long d)
{
    while (x <= maxn)
    {
        c[x] += d;
        x += lowbit(x);
    }
}

long long query(long long x)
{
    long long cnt = 0;
    while (x)
    {
        cnt += c[x];
        x -= lowbit(x);
    }
    return cnt;
}

void add2(long long x,long long d)
{
    while (x <= maxn)
    {
        num[x] += d;
        x += lowbit(x);
    }
}

long long query2(long long x)
{
    long long cnt = 0;
    while (x)
    {
        cnt += num[x];
        x -= lowbit(x);
    }
    return cnt;
}

bool cmp(node a,node b)
{
    return a.v < b.v;
}

int main()
{
    scanf("%lld",&n);
    for (int i = 1; i <= n; i++)
    {
    scanf("%lld%lld",&e[i].v,&e[i].x);
    maxn = max(maxn,e[i].x);
    }
    sort(e + 1,e + 1 + n,cmp);
    long long t = 0;
    for (int i = 1; i <= n; i++)
    {
        long long x = e[i].x,v = e[i].v;
        long long x1 = query(x - 1),num1 = query2(x - 1);
        long long num2 = i - 1 - num1,x2 = t - x1;
        t += e[i].x;
        ans += v * (num1 * x - x1 + x2 - num2 * x);
        add(x,x);
        add2(x,1);
    }
    printf("%lld\n",ans);

    return 0;
}

 

 
posted @ 2017-09-10 13:07  zbtrs  阅读(257)  评论(0编辑  收藏  举报