分析
对于 我们非常不好处理,可以考虑
分治。先按
由小到大排序。那么所有右侧的
一定大于左侧。在处理某一层时,再按
排序。这样处理答案就非常方便了。维护一个前缀和和一个后缀和。两个指针移一下。使用快排的时间复杂度为
,可以在分治过程中归并排序从此复杂度为
。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int inf = 0x3f3f3f3f;
int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-')f=1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return f ? -x : x ;
}
const int N = 5e4+100;
struct Node{
int v,x;
}s[N];
int n;
LL ans = 0;
bool cmpx(Node a,Node b) {
return a.x < b.x;
}
bool cmpv(Node a,Node b) {
return a.v < b.v;
}
void cdq(int l,int r)
{
if(r - l == 0) return;
int mid = l + r >> 1;
cdq(l,mid);cdq(mid+1,r);
sort(s+l,s+mid+1,cmpx);
sort(s+mid+1,s+r+1,cmpx);
LL s1 = 0,s2 = 0;
for(int i = l;i <= mid;i++) s1 += s[i].x;
LL pos = l;
LL n2 = 0,n1 = mid-l+1;
for(int i = mid+1;i <= r;i++)
{
while(pos <= mid && s[i].x > s[pos].x) {
s2 += s[pos].x;
s1 -= s[pos].x;
pos++;
n2++;n1--;
}
ans += 1LL * s[i].v * (s1 - s[i].x * n1);
ans += 1LL * s[i].v * (s[i].x * n2 - s2);
}
}
int main()
{
n = read();
for(int i = 1;i <= n;i++) {
s[i].v = read();s[i].x = read();
}
sort(s+1,s+1+n,cmpv);
cdq(1,n);
cout << ans << endl;
return 0;
}
京公网安备 11010502036488号