首页 > 代码库 > TreeArray1990

TreeArray1990

题意:FJn头牛,排列成一条直线(不会在同一个点),给出每头牛在直线上的坐标x。另外,每头牛还有一个自己的声调v,如果两头牛(ij)之间想要沟通的话,它们必须用同个音调max(v[i],v[j]),沟通起来消耗的能量为:max(v[i],v[j]) * 它们之间的距离。问要使所有的牛之间都能沟通(两两之间),总共需要消耗多少能量。

 

现在的问题是对于节点i,怎么知道他的x坐标X0分别于前面的i-1x坐标差的绝对值呢。想通了很简单,没想到,真是要人命。

 

其实只需求出前面小于X0的坐标个数count,和那些小于X0的坐标之和total,然后用alltotal记录当前ix坐标的所有和

 

距离为: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;

}

 

TreeArray1990