问题描述
FJ有n头牛,排列成一条直线(不会在同一个点),给出每头牛在直线上的坐标x。另外,每头牛还有一个自己的声调v,如果两头牛(i和j)之间想要沟通的话,它们必须用同个音调max(v[i],v[j]),沟通起来消耗的能量为:max(v[i],v[j]) * 它们之间的距离。问要使所有的牛之间都能沟通(两两之间),总共需要消耗多少能量。
问题分析
首先将牛按照音调由小到大排序,依次遍历每头牛,因为当前牛的音调最大,所以只需要计算它到其他牛的距离之和。依次计算当前牛和每头牛的距离肯定会超时,只需分别计算两边到当前坐标的距离之和就可了。通过树状数组维持两边点的数量以及两边点的坐标就可以快速计算出当前坐标到其他坐标的距离之和。
算法实现
import java.io.*;
import java.util.Arrays;
public class Main {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(System.out);
int read() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static void main(String[] args) throws IOException {
new Main().solve();
}
int MAXN = 20005;
int INF = 1000000007;
long ans = 0;
int N ;
long[] arr = new long[MAXN];
Pair[] pairs = new Pair[MAXN];
private void solve() throws IOException {
N = read();
for (int i = 0; i < N; i++) {
pairs[i] = new Pair(read(), read());
}
Arrays.sort(pairs, 0, N);
init();
for (int i = 0; i < N; i++) {
long lcnt = sum(bit1, pairs[i].x);
long rcnt = sum(bit1, MAXN) - lcnt;
long lsum = sum(bit2, pairs[i].x);
long rsum = sum(bit2, MAXN) - lsum;
ans += pairs[i].v * (lcnt*pairs[i].x - lsum + rsum - rcnt*pairs[i].x);
add(bit1,pairs[i].x, 1);
add(bit2,pairs[i].x, pairs[i].x);
}
out.println(ans);
out.flush();
}
int[] bit1 = new int[MAXN+1];
int[] bit2 = new int[MAXN+1];
private void init(){
Arrays.fill(bit1,0);
Arrays.fill(bit2,0);
}
private long sum(int[] bit, int i){
long res = 0;
while (i > 0){
res = res + bit[i];
i -= i&-i;
}
return res;
}
private void add(int[] bit, int i, int a){
while (i<=MAXN){
bit[i] += a;
i += i&-i;
}
}
class Pair implements Comparable<Pair>{
int v,x;
public Pair(int v, int x) {
this.v = v;
this.x = x;
}
@Override
public int compareTo(Pair o) {
return v - o.v;
}
}
}