TreeArray1990

题意: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;

}

时间: 2024-10-04 16:21:54

TreeArray1990的相关文章