luogu P2345 奶牛集会
题目背景
MooFest, 2004 Open
题目描述
约翰的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
输出格式:
• 单个整数:表示所有奶牛产生的音量之和
输入输出样例
说明
朴素O(N2)
类似于归并排序的二分O(N logN)
树状数组O(N logN)
zanwujieshi
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; long long n,c[50010],maxn,num[50010],ans; struct node { long long v,x; }e[20010]; long long lowbit(long long x) { return x & (-x); } void add(long long x,long long d) { while (x <= maxn) { c[x] += d; x += lowbit(x); } } long long query(long long x) { long long cnt = 0; while (x) { cnt += c[x]; x -= lowbit(x); } return cnt; } void add2(long long x,long long d) { while (x <= maxn) { num[x] += d; x += lowbit(x); } } long long query2(long long x) { long long cnt = 0; while (x) { cnt += num[x]; x -= lowbit(x); } return cnt; } bool cmp(node a,node b) { return a.v < b.v; } int main() { scanf("%lld",&n); for (int i = 1; i <= n; i++) { scanf("%lld%lld",&e[i].v,&e[i].x); maxn = max(maxn,e[i].x); } sort(e + 1,e + 1 + n,cmp); long long t = 0; for (int i = 1; i <= n; i++) { long long x = e[i].x,v = e[i].v; long long x1 = query(x - 1),num1 = query2(x - 1); long long num2 = i - 1 - num1,x2 = t - x1; t += e[i].x; ans += v * (num1 * x - x1 + x2 - num2 * x); add(x,x); add2(x,1); } printf("%lld\n",ans); return 0; }