题意:FJ有n头牛,排列成一条直线(不会在同一个点),给出每头牛在直线上的坐标x。另外,每头牛还有一个自己的声调v,如果两头牛(i和j)之间想要沟通的话,它们必须用同个音调max(v[i],v[j]),沟通起来消耗的能量为:max(v[i],v[j]) * 它们之间的距离。问要使所有的牛之间都能沟通(两两之间),总共需要消耗多少能量。
现在的问题是对于节点i,怎么知道他的x坐标X0分别于前面的i-1个x坐标差的绝对值呢。想通了很简单,没想到,真是要人命。
其实只需求出前面小于X0的坐标个数count,和那些小于X0的坐标之和total,然后用alltotal记录当前i个x坐标的所有和
距离为:count*X0 - total + alltotal - total - (i - count)*X0;
//分两部分来计算,小于X0的,和大于X0的。
I-count表示比i坐标大的点共有多少个
/***********************************************
* By: chenguolin *
* Date: 2013-08-19 *
* Address: http://blog.csdn.net/chenguolinblog *
***********************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long int64;
const int MAXN = 20010;
struct Node{
int x;
int v;
bool operator<(const Node& s)const{
return v < s.v;
//按声音大小排序,不是坐标。因为声音大的才需要接着考虑声音小的
}
};
Node node[MAXN];
int n;
int treeCount[MAXN];
int treeDis[MAXN];
int lowbit(int x){
return x&(-x);
}
__int64 getSum(int x , int *arr){
int64 sum = 0;
while(x){
sum += arr[x];
x -= lowbit(x);
}
return sum;
}
void add(int x , int val , int *arr){
while(x < MAXN){
arr[x] += val;
x += lowbit(x);
}
}
__int64 solve()
{
int64 ans = 0;
int64 totalDis = 0;
memset(treeCount , 0 , sizeof(treeCount));
memset(treeDis , 0 , sizeof(treeDis));
sort(node , node+n);
for(int i = 0 ; i < n ; i++){//treecount是树状数组,treecount[i]表示排序后 原始坐标为i的个数。求sum_cout(i)即是求原始坐标小于i的个数
int64 count = getSum(node[i].x , treeCount); //treedis[i]表示坐标为i的元素的原始坐标是多少(如果有一个点是i,两个的话是2*i)
int64 dis = getSum(node[i].x , treeDis);//,求sum_dis(i)即是求原始小标小于i的这些点坐标之和
// left
ans += node[i].v*(count*node[i].x-dis);
// right
ans += node[i].v*((totalDis-dis-(i-count)*node[i].x));
// update
totalDis += node[i].x;//所有点的坐标和要加上这个新加上的,由于经过排序,计算声音大的牛必然要考虑声音更小的牛,所以之前的牛全部比当前牛声音小
add(node[i].x , 1 , treeCount)//add函数的实值是node[i].x即原始坐标,原始坐标为node[i].x的元素加1
add(node[i].x , node[i].x , treeDis);//treedis存的坐标值,不是元素个数,因此原始坐标为node[i].x的坐标值加上node[i].x
}
return ans;
}
int main(){
while(scanf("%d" , &n) != EOF)
{
for(int i = 0 ; i < n ; i++)
scanf("%d%d" , &node[i].v , &node[i].x);
printf("%lld\n" , solve());
}
return 0;
}