题目描述
约翰的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(N2)
类似于归并排序的二分O(N logN)
树状数组O(N logN)
开两个树状数组,一个存坐标值之和,一个存奶牛数量之和。按照声音升序进行操作。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int max_coor;
struct node{
int coor;
int sound;
}a[maxn];
ll sum[maxn];
ll num[maxn];
int n;
int lowbit(int x) {
return x & -x;
}
bool com(node x, node y) {
return x.sound < y.sound;
}
void update_sum(int i, int val) {
for(; i <= max_coor; i += lowbit(i)) {
sum[i] += val;
}
}
void update_num(int i) {
for(; i <= max_coor; i += lowbit(i))
num[i]++;
}
ll query_sum(int l, int r) {
ll ans = 0;
for(; r >= 1; r -= lowbit(r))
ans += sum[r];
for(l--; l >= 1; l -= lowbit(l))
ans -= sum[l];
return ans;
}
ll query_num(int l, int r) {
ll ans = 0;
for(; r >= 1; r -= lowbit(r))
ans += num[r];
for(l--; l >= 1; l -= lowbit(l))
ans -= num[l];
return ans;
}
int main() {
cin >> n;
ll ans = 0;
for(int i = 1; i <= n; i++)
cin >> a[i].sound >> a[i].coor, max_coor = max(max_coor, a[i].coor);
sort(a + 1, a + 1 + n, com);
// for(int i = 1 ;i <= n; i++)
// cout << a[i].sound << " " << a[i].coor << endl;
for(int i = 1; i <= n; i++) {
update_sum(a[i].coor, a[i].coor);
update_num(a[i].coor);
// cout << sum[5] << endl;
if(i > 1) {
ans += a[i].sound * (query_sum(a[i].coor + 1, max_coor) - a[i].coor * query_num(a[i].coor + 1, max_coor));
// cout << query_sum(a[i].coor + 1, max_coor) << " " << query_num(a[i].coor + 1, max_coor) << " " << a[i].coor << " " << ans << " ";
ans += a[i].sound * (a[i].coor * query_num(1, a[i].coor - 1) - query_sum(1, a[i].coor - 1));
// cout << ans << " " << query_sum(1, a[i].coor - 1) << " " << query_num(1, a[i].coor - 1) << endl;
}
}
cout << ans << endl;
return 0;
}